JavaClassReader.st
author Claus Gittinger <cg@exept.de>
Thu, 24 Nov 2011 12:54:24 +0100
changeset 2290 cd61fd0b66ac
parent 2151 c0b6570c6f9b
child 2353 fa7400d022a0
permissions -rw-r--r--
fixed: #version_SVN ($ to §)

"
 COPYRIGHT (c) 1996-2011 by Claus Gittinger
 COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
                            SWING Research Group, Czech Technical University in Prague

 Parts of the code written by Claus Gittinger are under following
 license:

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.

 Parts of the code written at SWING Reasearch Group [1] are MIT licensed:

 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.

 [1] Code written at SWING Research Group contain a signature
     of one of the above copright owners.
"
"{ Package: 'stx:libjava' }"

Object subclass:#JavaClassReader
	instanceVariableNames:'inStream msb constants majorVsn minorVsn constNeeds2Slots
		constSlot classBeingLoaded'
	classVariableNames:'Verbose AnnotationsVerbose Silent AbsolutelySilent
		LazyClassLoading InvalidClassFormatSignal ClassLoaderQuerySignal
		JavaArchiveCache'
	poolDictionaries:''
	category:'Languages-Java-Support'
!

!JavaClassReader class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1996-2011 by Claus Gittinger
 COPYRIGHT (c) 2010-2011 by Jan Vrany, Jan Kurs and Marcel Hlopko
                            SWING Research Group, Czech Technical University in Prague

 Parts of the code written by Claus Gittinger are under following
 license:

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.

 Parts of the code written at SWING Reasearch Group [1] are MIT licensed:

 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.

 [1] Code written at SWING Research Group contain a signature
     of one of the above copright owners.

"
! !

!JavaClassReader class methodsFor:'initialization'!

initialize
    InvalidClassFormatSignal := Signal new mayProceed: true.
    InvalidClassFormatSignal notifierString: 'class load failure'.
    InvalidClassFormatSignal nameClass: self message: #invalidClassFormatSignal.
    Verbose := false.
    Silent := true.
    AbsolutelySilent := false.
    
    "/LazyClassLoading := false.
    
    LazyClassLoading := true.
    ClassLoaderQuerySignal := QuerySignal new.
    JavaArchiveCache := CacheDictionary new: 32.
    AnnotationsVerbose := false.

    "
     JavaClassReader initialize"

    "Modified: / 27-01-1998 / 17:54:23 / cg"
    "Modified: / 17-12-2010 / 17:37:45 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 10-05-2011 / 23:59:53 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 26-07-2011 / 17:21:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!JavaClassReader class methodsFor:'Signal constants'!

classLoaderQuerySignal
    ^ ClassLoaderQuerySignal

    "Created: 14.8.1997 / 19:56:03 / cg"
!

invalidClassFormatSignal
    ^ InvalidClassFormatSignal

    "Created: 3.8.1997 / 18:17:21 / cg"
! !

!JavaClassReader class methodsFor:'constants'!

fileMajorVersions
    ^#( 
        46  "Java 1.2"
        47  "???"
        48  "???"
        49  "Java 5"
        50  "Java 6"
      ).

    "
     JSR 202:
     The Java virtual machine implementation of Sun's JDK release 1.0.2 supports
     class file format versions 45.0 through 45.3 inclusive. Sun's JDK releases
     1.1.X can support class file formats of versions in the range 45.0 through
     45.65535 inclusive. For k > 1 implementations of version 1.k of the Java 2
     platform can support class file formats of versions in the range 45.0 through
     44+k.0 inclusive.
"

    "Created: / 19-10-2010 / 21:40:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 01-06-2011 / 21:44:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 02-06-2011 / 22:50:17 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 18-08-2011 / 19:32:37 / jv"
!

fileMinorVersions
    ^ #(
        3 "Java 1.2"
        0 "Java 6"
    )

    "Created: / 19-10-2010 / 21:41:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

magic_LSB
    ^ 16rBEBAFECA

    "Modified: / 7.5.1998 / 13:14:27 / cg"
    "Created: / 7.5.1998 / 13:15:05 / cg"
!

magic_MSB
    ^ 16rCAFEBABE

    "Modified: / 7.5.1998 / 13:14:27 / cg"
! !

!JavaClassReader class methodsFor:'debugging'!

annotationsVerbose:aBoolean 
    AnnotationsVerbose := aBoolean

    "
     Java flushClasses.
     JavaClassReader verbose:true
     JavaClassReader verbose:false"

    "Created: / 25-02-2011 / 12:25:23 / Marcel Hlopko <hlopik@gmail.com>"
!

verbose:aBoolean
    Verbose := aBoolean

    "
     Java flushClasses.
     JavaClassReader verbose:true
     JavaClassReader verbose:false
    "
! !

!JavaClassReader class methodsFor:'file reading'!

loadClass:aClassName
    "reads a class, installs and returns it.
     The classes string constants are resolved & <clinit> is called,
     if it implements it."

    |rslt loader|

    loader := ClassLoaderQuerySignal query.
    loader isNil ifTrue:[
        ^ self loadSystemClass:aClassName
    ].

    ^ loader loadClass:aClassName

    "
     JavaClassReader loadClass:'awt/Component'
     JavaClassReader loadClass:'awt/Button'
     JavaClassReader loadClass:'browser/AddButton'

     JavaClassReader loadClass:'java/lang/Object'
     JavaClassReader loadClass:'java/lang/AbstractMethodError'
     JavaClassReader loadClass:'java/lang/Thread'
    "

    "Created: / 15.4.1996 / 14:58:53 / cg"
    "Modified: / 20.10.1998 / 17:24:54 / cg"
!

loadClassLazy: internalJavaClassName 
    ^ self loadClassLazy: internalJavaClassName ignoring: Set new.

    "Created: / 08-04-2011 / 18:00:28 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 11-04-2011 / 19:31:04 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

loadClassLazy: className classpath: classpath ignoring: classesBeingLoaded 
    "private helper:
      reads a class, installs and returns it.
      The class is searched along the ClassPath.

     This is a partial load (to load other classes):
     - The classes stringConstants are not fixed to be JavaStrings
       (i.e they are still ST-Strings).
     - The class is NOT initialized."
    
    | rslt  clsName  cls  loadedClass |

    clsName := className utf8Encoded.
    (clsName endsWith: ';') 
        ifTrue: 
            [ (clsName startsWith: '[L') 
                ifTrue: [ clsName := clsName copyFrom: 3 to: clsName size - 1. ]
                ifFalse: 
                    [ ('oops - loading of ' , clsName , ' attempted') printNL.
                    self halt: 'should not happen'.
                    ^ nil. ] ].
    (clsName endsWith: '[]') 
        ifTrue: 
            [ ('oops - loading of ' , clsName , ' attempted') printNL.
            self halt: 'should not happen'.
            ^ nil ].
    (clsName includes: $.) 
        ifTrue: [ clsName := clsName asString copyReplaceAll: $. with: $/ ].
    (classesBeingLoaded notNil and: [ classesBeingLoaded includes: clsName ]) 
        ifTrue: 
            [ ('oops - recursive load of ' , clsName , ' attempted') printNL.
            self halt: 'should not happen'.
            ^ JavaUnresolvedClassConstant fullName: clsName ].
    (cls := Java at: clsName) notNil 
        ifTrue: 
            [ ('oops - ' , clsName , ' is already loaded') printNL.
            
            "/self halt:clsName , ' is already loaded - should not happen'.
            
            ^ cls ].
    classesBeingLoaded isNil 
        ifTrue: [ loadedClass := Set with: clsName ]
        ifFalse: 
            [ loadedClass := Set withAll: classesBeingLoaded.
            loadedClass add: clsName. ].
    classpath do: 
            [:path | 
            | nm  p  zar  entry  zipFile  read |

            Verbose == true 
                ifTrue: [ Transcript showCR: 'trying ' , path asFilename pathName , ' ...'. ].
            p := path.
            p asFilename isDirectory 
                ifTrue: 
                    [ (p endsWith: Filename separator) 
                        ifFalse: [ p := p , (Filename separator asString) ].
                    (Array 
                        with: clsName
                        with: clsName asLowercase
                        with: clsName asUppercase) do: 
                                [:tryName | 
                                nm := p , tryName , '.class'.
                                Verbose == true ifTrue: [ Transcript showCR: 'trying ' , nm , ' ...'. ].
                                nm asFilename exists 
                                    ifTrue: 
                                        [ (Java isExcludedFromClassPath: nm) 
                                            ifFalse: 
                                                [ rslt := self loadFileLazy: nm ignoring: loadedClass.
                                                rslt notNil ifTrue: [ ^ rslt ]. ] ]. ] ]
                ifFalse: 
                    [ Verbose == true 
                        ifTrue: 
                            [ Transcript 
                                showCR: 'trying ' , (p asFilename withSuffix: 'jar') pathName , ' ...'.
                            Transcript 
                                showCR: 'and ' , (p asFilename withSuffix: 'zip') pathName , ' ...'. ].
                    ((zipFile := p asFilename withSuffix: 'jar') exists 
                        or: [ (zipFile := p asFilename withSuffix: 'zip') exists ]) 
                            ifTrue: 
                                [
                                zar := JavaArchiveCache at: zipFile
                                            ifAbsentPut: [ ZipArchive oldFileNamed: zipFile ].
                                read := 
                                        [ nm := clsName , '.class'.
                                        entry := zar extract: nm.
                                        entry notNil 
                                            ifTrue: 
                                                [ (Java isExcludedFromClassPath: nm) 
                                                    ifFalse: 
                                                        [ rslt := self loadStreamLazy: (entry readStream) ignoring: loadedClass.
                                                        rslt notNil ifTrue: [ ^ rslt ]. ] ] ].
                                JavaClassReader invalidClassFormatSignal handle: 
                                        [ "Kludge, sometimes zar gets corrupted"
                                    
                                        zar := JavaArchiveCache at: zipFile put: (ZipArchive oldFileNamed: zipFile).
                                        read value ]
                                    do: [ read value ]. ] ] ].
    ^nil.

    "Modified: / 14-08-1997 / 11:38:42 / stefan"
    "Modified: / 17-09-1998 / 20:51:25 / cg"
    "Modified: / 21-03-2011 / 12:42:12 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Created: / 12-08-2011 / 08:48:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

loadClassLazy: aClassName ignoring: classesBeingLoaded 

    | class loader |
    class := self loadClassLazy: aClassName classpath: Java release classPath ignoring: classesBeingLoaded.
    class notNil ifTrue:[^class].
    class := self loadClassLazy: aClassName classpath: Java classPath ignoring: classesBeingLoaded.
    class isNil ifTrue:[^nil].
    loader := (Java classForName:'java.lang.ClassLoader') instVarNamed: #scl.
    loader ifNil:[
        loader := (Java classForName:'java.lang.ClassLoader') perform: #'getSystemClassLoader()Ljava/lang/ClassLoader;'.
    ].
    class classLoader: loader.
    ^ class

    "Modified: / 14-08-1997 / 11:38:42 / stefan"
    "Modified: / 17-09-1998 / 20:51:25 / cg"
    "Modified: / 21-03-2011 / 12:42:12 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 12-08-2011 / 09:06:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

loadClassesIn: directory 
    "load all classes (.class files, strictly speaking) found in given directory.
     The argument is string containing the name of the directory.

    Returns a set of loaded classes."
    
    ^self loadClassesIn: directory  matching: '*'

    "Modified: / 11-06-2011 / 13:35:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

loadClassesIn: directory matching: pattern
    "load all classes (.class files, strictly speaking) found in given directory.
     The arguments are a string containing the name of the directory
     and a class name pattern. Only classes matching the pattern are loaded.
     class names are matched using String>>matches:.
    
     Returns a set of loaded classes."
    
    | dir  dirString  className  loadedClasses |

    dir := directory asFilename asAbsoluteFilename.
    loadedClasses := Set new.
    Java addToClassPath: dir pathName.
    dir recursiveDirectoryContentsAsFilenamesDo: 
            [:filename |
            (filename isRegularFile and: [ filename suffix = #class ]) 
                ifTrue: 
                    [ dirString := dir pathName.
                    className := filename withoutSuffix pathName.
                    className := className subString: dirString size + 2 to: className size.
                    className := className copyReplaceAll: (Filename separator) with: $..
                    (className matches: pattern) ifTrue:
                        [loadedClasses add: (self loadClass: className)]]].

    ^ loadedClasses.

    "Modified: / 29-04-2011 / 17:43:32 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Created: / 11-06-2011 / 13:34:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 11-06-2011 / 16:19:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

loadFile:aFilename
    "reads a class from aFilename, installs and returns it.
     The classes strings are fixed and its class-init function is called."

    self loadFileLazy:aFilename ignoring:(Set new).
    self postLoadActions
!

loadFileLazy:aFilename ignoring:classesBeingLoaded
    "reads a class from aFilename, installs and returns it.
     Strings are fixed and classrefs are fixed, 
     but NO no class-init functions are called."

    |aClass pool|

    aClass := self readFile:aFilename ignoring:classesBeingLoaded.
    aClass notNil ifTrue:[
        aClass isJavaClass ifTrue:[
            "/ a java class
            Java at:(aClass fullName asSymbol) put:aClass.

            classesBeingLoaded remove:aClass fullName ifAbsent:nil.

            JavaUnresolvedConstant resolveFor:aClass.
        ] ifFalse:[    
            "/ a smalltalk class
            "/ self halt.
aClass inspect.
        ]
    ].
    ^ aClass

    "
     JavaClassReader loadFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'

     '/phys/ibm3/java/lib/java/lang' asFilename
        directoryContents do:[:nm |
            (nm endsWith:'.class') ifTrue:[
                ('/phys/ibm3/java/lib/java/lang/' , nm) printNL.
                JavaClassReader loadFile:'/phys/ibm3/java/lib/java/lang/' , nm
            ]
        ].

     '/phys/ibm3/java/lib/java/io' asFilename
        directoryContents do:[:nm |
            (nm endsWith:'.class') ifTrue:[
                ('/phys/ibm3/java/lib/java/io/' , nm) printNL.
                JavaClassReader loadFile:'/phys/ibm3/java/lib/java/io/' , nm
            ]
        ].

     '/phys/ibm3/java/lib/java/net' asFilename
        directoryContents do:[:nm |
            (nm endsWith:'.class') ifTrue:[
                ('/phys/ibm3/java/lib/java/net/' , nm) printNL.
                JavaClassReader loadFile:'/phys/ibm3/java/lib/java/net/' , nm
            ]
        ].

     '/phys/ibm3/java/lib/java/util' asFilename
        directoryContents do:[:nm |
            (nm endsWith:'.class') ifTrue:[
                ('/phys/ibm3/java/lib/java/util/' , nm) printNL.
                JavaClassReader loadFile:'/phys/ibm3/java/lib/java/util/' , nm
            ]
        ].

     '/phys/ibm3/java/lib/java/awt' asFilename
        directoryContents do:[:nm |
            (nm endsWith:'.class') ifTrue:[
                ('/phys/ibm3/java/lib/java/awt/' , nm) printNL.
                JavaClassReader loadFile:'/phys/ibm3/java/lib/java/awt/' , nm
            ]
        ].

     '/phys/ibm3/java/lib/java/applet' asFilename
        directoryContents do:[:nm |
            (nm endsWith:'.class') ifTrue:[
                ('/phys/ibm3/java/lib/java/applet/' , nm) printNL.
                JavaClassReader loadFile:'/phys/ibm3/java/lib/java/applet/' , nm
            ]
        ].

     JavaClassReader loadFile:'/phys/ibm3/java/lib/java/lang/AbstractMethodError.class'
     JavaClassReader loadFile:'/phys/ibm3/java/lib/java/lang/Thread.class'
    "

    "Created: / 15.4.1996 / 14:58:53 / cg"
    "Modified: / 12.5.1998 / 22:06:52 / cg"
!

loadStreamLazy:aStream ignoring:classesBeingLoaded
    "reads a class from aStream, installs and returns it.
     Strings are fixed and classrefs are fixed, 
     but NO no class-init functions are called."

    |javaClass pool|

    javaClass := self readStream:aStream ignoring:classesBeingLoaded.
    javaClass notNil ifTrue:[
        Java at:(javaClass fullName asSymbol) put:javaClass.

        classesBeingLoaded remove:javaClass fullName ifAbsent:nil.

        JavaUnresolvedConstant resolveFor:javaClass.
    ].
    ^ javaClass

    "Created: / 30.3.1998 / 17:59:02 / cg"
!

loadSystemClass: aClassName 
    "reads a class, installs and returns it.
     The classes string constants are resolved & <clinit> is called,
     if it implements it.
     This only loads local classes (i.e. any Java classReader is not used)"
    
    | class classLoaderClass |

    class := JavaClassReader loadClassLazy: aClassName ignoring: (Set new).
    class isNil ifTrue: [ ^nil].
    self assert: class constantPool owner == class.
    JavaClassReader postLoadActions.
"/    "Set the classloader iff the VM is booted"
"/    "Rubbish, do not do that"        
"/    JavaVM booted ifTrue:[
"/        classLoaderClass := Java at:'java.lang.ClassLoader'.
"/        classLoaderClass notNil ifTrue:[
"/            class classLoader: (classLoaderClass instVarNamed:#scl).
"/        ].
"/    ].
    ^ class

    "
     JavaClassReader loadSystemClass:'awt/Component'
     JavaClassReader loadSystemClass:'awt/Button'
     JavaClassReader loadSystemClass:'browser/AddButton'

     JavaClassReader loadSystemClass:'java/lang/Object'
     JavaClassReader loadSystemClass:'java/lang/AbstractMethodError'
     JavaClassReader loadSystemClass:'java/lang/Thread'"

    "Created: / 20-10-1998 / 17:24:40 / cg"
    "Modified: / 13-05-2011 / 17:50:55 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 08-08-2011 / 17:13:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

loadSystemClass: aClassName classpath: classpath 
    "reads a class, installs and returns it.
     The classes string constants are resolved & <clinit> is called,
     if it implements it.
     This only loads local classes (i.e. any Java classReader is not used)"
    
    | class loader |

    class := JavaClassReader loadClassLazy: aClassName classpath: classpath ignoring: (Set new).
    class isNil ifTrue: [ ^nil].
    classpath = Java release classPath ifFalse:[
        loader := (Java classForName:'java.lang.ClassLoader') instVarNamed: #scl.
        loader ifNil:[
            loader := (Java classForName:'java.lang.ClassLoader') perform: #'getSystemClassLoader()Ljava/lang/ClassLoader;'.
        ].
        class classLoader: loader.
    ].
    self assert: class constantPool owner == class.
    JavaClassReader postLoadActions.
"/    "Set the classloader iff the VM is booted"
"/    "Rubbish, do not do that"        
"/    JavaVM booted ifTrue:[
"/        classLoaderClass := Java at:'java.lang.ClassLoader'.
"/        classLoaderClass notNil ifTrue:[
"/            class classLoader: (classLoaderClass instVarNamed:#scl).
"/        ].
"/    ].
    ^ class

    "
     JavaClassReader loadSystemClass:'awt/Component'
     JavaClassReader loadSystemClass:'awt/Button'
     JavaClassReader loadSystemClass:'browser/AddButton'

     JavaClassReader loadSystemClass:'java/lang/Object'
     JavaClassReader loadSystemClass:'java/lang/AbstractMethodError'
     JavaClassReader loadSystemClass:'java/lang/Thread'"

    "Created: / 20-10-1998 / 17:24:40 / cg"
    "Modified: / 13-05-2011 / 17:50:55 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Created: / 12-08-2011 / 09:05:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

postLoadActions
    "Resolve all classes' string constants.
     Perform all class initialization functions (of those which are not
     yet initialized)."

    ^ self postLoadActions:true

    "Modified: 15.8.1997 / 01:02:17 / cg"
!

postLoadActions:loadUnresolved
    "Resolve all classes' string constants.
     Perform all class initialization functions 
     (of those which are not yet initialized)."

    |classes prevUnresolved newUnresolved loader|

    "/ need at least java.lang.String, for valid constants
    Java java_lang_String isNil ifTrue:[
        self loadClassLazy:'java.lang.String' ignoring:(Set new).
    ].

    LazyClassLoading ifFalse:[
        loader := ClassLoaderQuerySignal query.

        prevUnresolved := nil.
        newUnresolved := JavaUnresolvedConstant unresolvedClassNames asArray.
        loadUnresolved ifTrue:[
            [prevUnresolved ~= newUnresolved] whileTrue:[
                newUnresolved do:[:nextUnresolved |
                    |classURL|

                    (Java at:nextUnresolved) isNil ifTrue:[ "/ could have been loaded in the meantime
                        Silent ifFalse:[
                            'loading unresolved: ' print. nextUnresolved printCR.
                        ].
                        loader isNil ifTrue:[
                            self
                                loadClassLazy:nextUnresolved
                                ignoring:(Set new).
                        ] ifFalse:[
                            "/
                            "/ the aquired loader is a javaClassLoader
                            "/ which expects an URL as arg.
                            "/
                            "/ classURL := Java as_URL:('file:' , nextUnresolved asString , '.class').
                            "/ loader loadClass:classURL
                            loader
                                perform:#'loadClass(Ljava/lang/String;)Ljava/lang/Class;'
                                with:(Java as_String:(nextUnresolved asString)).
                        ]
                    ]
                ].
                prevUnresolved := newUnresolved.
                newUnresolved := JavaUnresolvedConstant unresolvedClassNames asArray.
            ].
        ].
false ifTrue:[
        newUnresolved size == 0 ifTrue:[
            "/ nothing unresolved

            (classes := Java allClasses) notNil ifTrue:[
                "/ init all new classes
                "/ fetch again - there could be new ones ...

                classes := Java allClasses.
                classes do:[:aJavaClass |
                    aJavaClass isInitialized ifFalse:[
                        Silent ifFalse:[
                            'performing class initialization of ' print. aJavaClass fullName printCR.
                        ].
                        aJavaClass classInit
                    ]
                ]
            ]
        ].
].
    ]

    "Created: / 15.8.1997 / 01:01:44 / cg"
    "Modified: / 21.10.1998 / 01:18:35 / cg"
!

readFile:aFilename ignoring:classesBeingLoaded
    "reads a class from aFilename and returns it.
     The JavaClass is NOT installed as global and unresolved
     refs are NOT patched."

    |inStream javaClass|

    "Silent"false ifFalse:[
        'reading ' print. aFilename print. ' ...' printCR.
    ].

    [
        inStream := aFilename asFilename readStream.
    ] on:StreamError do:[:ex|
        ('JAVA [info]: no file: ' , aFilename asString) printCR.
        self halt.
        ^ nil
    ].

    javaClass := self new readStream:inStream ignoring:classesBeingLoaded.
    (javaClass notNil and:[javaClass isJavaClass]) ifTrue:[
        javaClass setBinaryFilePath:(inStream pathName).
    ].
    inStream close.

    AbsolutelySilent ifFalse:[
        '  ... loaded ' print. javaClass displayString printNL.
    ].


    ^ javaClass

    "Created: / 15-04-1996 / 14:58:53 / cg"
    "Modified: / 09-05-1998 / 01:44:24 / cg"
    "Modified: / 09-08-2011 / 15:18:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readStream:aStream
    "reads a class from aStream and returns it.
     The JavaClass is installed as global.
     If new classes are required to be loaded, a new standard loader
     is created."

    ^ self readStream:aStream loader:nil

    "Modified: 14.8.1997 / 19:51:50 / cg"
!

readStream: aStream ignoring: classesBeingLoaded 
    "reads a class from aStream and returns it.
     The JavaClass is not installed as global"
    
    | javaClass |

    javaClass := JavaClassReader new readStream: aStream ignoring: classesBeingLoaded.
    AbsolutelySilent 
        ifFalse: 
            [ '  ... loaded ' print.
            javaClass displayString printNL. ].
    ^ javaClass

    "Modified: / 30-03-1998 / 18:14:40 / cg"
    "Modified: / 09-05-2011 / 23:15:30 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 26-07-2011 / 17:21:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readStream:aStream loader:aClassLoader
    "reads a class from aStream and returns it.
     The JavaClass is installed as global.
     If new classes are required to be loaded, aClassLoader is
     asked to do it. If aClassLoader is nil, a new standard loader
     is created."

    ^ self
	readStream:aStream 
	loader:aClassLoader 
	loadUnresolved:true

    "Modified: 15.8.1997 / 01:00:35 / cg"
!

readStream: aStream loader: aClassLoader loadUnresolved: loadUnresolved 
    "reads a class from aStream and returns it.
     The JavaClass is installed as global.
     If new classes are required to be loaded, aClassLoader is
     asked to do it. If aClassLoader is nil, a new standard loader
     is created."
    
    | javaClass |

    ClassLoaderQuerySignal answer: aClassLoader
        do: 
            [ javaClass := self readStream: aStream ignoring: (Set new).
            javaClass notNil 
                ifTrue: 
                    [ JavaClassReader postLoadActions: loadUnresolved.
                    Java at: (javaClass fullName asSymbol) put: javaClass.
                    JavaUnresolvedConstant resolveFor: javaClass. ]. ].
    ^ javaClass

    "Created: / 15-08-1997 / 00:59:24 / cg"
    "Modified: / 23-01-1998 / 17:14:09 / cg"
    "Modified: / 09-05-2011 / 23:15:23 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 26-07-2011 / 17:21:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

resolveClass:aJavaClass
    "Resolve a particular classes' constants.
     Perform all class initialization functions 
     (of those which are not yet initialized)."

    |loader classToLoad|

    LazyClassLoading ifFalse:[
        loader := (aJavaClass classLoader). "/ ? (ClassLoaderQuerySignal raise).

        [
            classToLoad := nil.
            aJavaClass constantPool do:[:item |
                |itemClass |

                itemClass := item class.
                itemClass == JavaUnresolvedClassConstant ifTrue:[
                    classToLoad := item className.
"/                ] ifFalse:[
"/                    itemClass == JavaUnresolvedMethodrefConstant ifTrue:[
"/self halt.
"/                    ] ifFalse:[
"/                        itemClass == JavaUnresolvedInterfaceMethodrefConstant ifTrue:[
"/self halt.
"/                        ]
"/                    ]
                ].
            ].

            classToLoad notNil ifTrue:[
                loader isNil ifTrue:[
                    self
                        loadClassLazy:classToLoad
                        ignoring:(Set new).
                ] ifFalse:[
                    "/
                    "/ the aquired loader is a javaClassLoader
                    "/ which expects an URL as arg.
                    "/
                    "/ classURL := Java as_URL:('file:' , nextUnresolved asString , '.class').
                    "/ loader loadClass:classURL
                    loader
                        perform:#'loadClass(Ljava/lang/String;)Ljava/lang/Class;'
                        with:(Java as_String:(classToLoad asString)).
                ]
            ].
            classToLoad notNil.
        ] whileTrue.

        aJavaClass isInitialized ifFalse:[
            Silent ifFalse:[
                'performing class initialization of ' print. aJavaClass fullName printCR.
            ].
            aJavaClass classInit
        ].
    ]

    "Created: / 20.10.1998 / 17:53:22 / cg"
    "Modified: / 20.10.1998 / 17:59:09 / cg"
! !

!JavaClassReader class methodsFor:'mode setting'!

useOldClassReader
    self error: 'Old class reader should not be used anymore!!'.
UsedJavaClassReaderClass := JavaClassReader.

    "Created: / 09-05-2011 / 23:11:04 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaClassReader methodsFor:'accessing'!

constants   
^ constants.

    "Created: / 10-05-2011 / 13:48:30 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

constants: aJavaConstantPool
    constants := aJavaConstantPool.

    "Created: / 10-05-2011 / 13:48:46 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

stream
^ inStream.

    "Created: / 09-05-2011 / 23:22:38 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

stream:aReadStream
    inStream := aReadStream.

    "Created: / 09-05-2011 / 23:23:11 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaClassReader methodsFor:'file reading'!

readClassFileIgnoring: classesbeingLoaded 
    "reads a class from inStream and returns it.
     The JavaClass is not installed as global and its constants
     (especially strings) may not be fully resolved."
    
    | magic  access_flags  this_class_index  super_class  super_class_index  this_class_ref  existingSuperClass  fields  interfaces  staticFields  nStatic  superClassName  thisClassName  existing_class  thisMetaClass |

    "/
    "/ read magic, determine byte order
    "/
    msb := true.
    magic := inStream nextUnsignedLongMSB: true.
    magic = (self class magic_MSB) 
        ifFalse: 
            [ magic = (self class magic_LSB) 
                ifFalse: 
                    [ InvalidClassFormatSignal raiseErrorString: 'not a java class file'.
                    ^ nil ].
            msb := false.
            Verbose ifTrue: [ Transcript showCR: 'file is lsb' ]. ]
        ifTrue: [ Verbose ifTrue: [ Transcript showCR: 'file is msb' ]. ].
    
    "/
    "/ get version
    "/
    
    minorVsn := inStream nextUnsignedShortMSB: msb.
    majorVsn := inStream nextUnsignedShortMSB: msb.
    ((self class fileMajorVersions includes: majorVsn) not 
        or: [ (self class fileMinorVersions includes: minorVsn) not ]) 
            ifTrue: 
                [ Transcript
                    show: 'warning this file has version ';
                    show: majorVsn;
                    show: '.';
                    showCR: minorVsn. ].
    Verbose 
        ifTrue: 
            [ Transcript
                show: 'version = ';
                show: (majorVsn printString);
                show: '.';
                showCR: (minorVsn printString). ].
    
    "/
    "/ get constant pool
    "/
    
    self readConstantPool.
    
    "/
    "/ access flags
    "/
    
    access_flags := inStream nextUnsignedShortMSB: msb.
    this_class_index := inStream nextUnsignedShortMSB: msb.
    super_class_index := inStream nextUnsignedShortMSB: msb.
    super_class_index == 0 
        ifTrue: [ super_class := nil ]
        ifFalse: 
            [ super_class := constants at: super_class_index.
            superClassName := super_class fullName.
            
            "/ special for ST-classes
            
            (superClassName startsWith: 'smalltalk.') 
                ifTrue: 
                    [ "/ a Smalltalk class
                    superClassName := superClassName copyFrom: 11.
                    existingSuperClass := Smalltalk at: superClassName asSymbol.
                    existingSuperClass notNil 
                        ifTrue: [ super_class := existingSuperClass ]
                        ifFalse: 
                            [ "/ self halt - must load superclass ...
                             ] ]
                ifFalse: 
                    [ "/ a JAVA class
                    super_class := Java classNamed: superClassName.
                    super_class ifNil: 
                            [ super_class := self loadSuperclassIdentifiedBy: (constants at: super_class_index)
                                ignoring: classesbeingLoaded ].
                    super_class ifNil: [ self halt: 'Cannot find super class?!!' ]. ]. ].
    
    "/
    "/ get interfaces
    "/
    
    interfaces := self readInterfaces.
    
    "/
    "/ get fields
    "/
    
    fields := self readFieldInfofields.
    
    "/
    "/ create the fields as instVars
    "/ static fields are created as class-InstVars
    "/
    
    staticFields := fields select: [:f | f isStatic ].
    nStatic := staticFields size.
    this_class_ref := constants at: this_class_index.
    thisClassName := this_class_ref fullName.
    
    "/ care for smalltalk classes ...
    
    (thisClassName startsWith: 'smalltalk.') 
        ifTrue: 
            [ thisClassName := thisClassName copyFrom: 11.
            existing_class := Smalltalk at: thisClassName asSymbol.
            existing_class notNil 
                ifTrue: 
                    [ self halt: ('overloading existing class: ' , thisClassName).
                    thisClassName := (thisClassName , '_new') asSymbol. ].
            thisMetaClass := Metaclass new.
            thisMetaClass setSuperclass: super_class class.
            thisMetaClass instSize: (super_class class instSize + nStatic).
            classBeingLoaded := thisMetaClass new.
            classBeingLoaded setSuperclass: super_class.
            classBeingLoaded setName: thisClassName asSymbol. ]
        ifFalse: 
            [ "/ a java class
            classBeingLoaded := JavaClass fullName: thisClassName numStatic: nStatic.

            fields := fields select: [:f | f isStatic not ].

            JavaClass setInstanceVariableStringFromFields: staticFields
                      in: classBeingLoaded class.

            classBeingLoaded setStaticFields: staticFields.
            classBeingLoaded initializeStaticFields.
            classBeingLoaded setAccessFlags: access_flags.
            classBeingLoaded setSuperclass: super_class.
            classBeingLoaded setConstantPool: constants.
            classBeingLoaded setFields: fields.
            classBeingLoaded setInterfaces: interfaces.
            ].
    
    "/
    "/ get methods
    "/
    
    self readMethodsFor: classBeingLoaded.
    self readAttributesFor: classBeingLoaded.
"/    classBeingLoaded constantPool 
"/        do: [:each | self updateOwnerInCPItem: each ].
    classBeingLoaded fields do: [:each | self updateOwnerInField: each ].
    classBeingLoaded staticFields do: [:each | self updateOwnerInField: each ].
    ^ classBeingLoaded.

    "
     JavaClassReader loadFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader loadFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'
     JavaClassReader loadFile:'foo.cls'

     JavaClassReader verbose:true.
     JavaClassReader loadFile:'/phys/ibm3/hotjava/classes/java/lang/ArithmeticException.class'
     JavaClassReader loadFile:'/phys/ibm3/java/lib/java/lang/ArithmeticException.class'"

    "Created: / 15-04-1996 / 15:02:47 / cg"
    "Modified: / 12-11-1998 / 21:14:45 / cg"
    "Modified: / 15-10-2010 / 17:37:38 / Jan Kurs <kurs.jan@post.cz>"
    "Modified: / 28-01-2011 / 15:09:48 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 18-05-2011 / 15:30:29 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 22-05-2011 / 14:23:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readStream:aStream ignoring:classesBeingLoaded
    "reads a class from aStream and returns it.
     The JavaClass is not installed as global"

    inStream := aStream.
    inStream binary.

    ^ self readClassFileIgnoring:classesBeingLoaded

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
    "

    "Created: 15.4.1996 / 15:00:55 / cg"
    "Modified: 15.4.1996 / 15:06:18 / cg"
! !

!JavaClassReader methodsFor:'file reading - attributes'!

readAnnotationDefaultAttributeFor:something 
    "/        ('JAVA [info]: unhandled attribute: AnnotationDefault') infoPrintCR.
    
    |len startPos endPos annotationDefault|

    self assert:something isJavaMethod
        description:'AnnotationDefault may only occure for methods!!'.
    len := inStream nextUnsignedLongMSB:msb.
    startPos := inStream position.
    annotationDefault := (something ensureHasAnnotations)
                default:(JavaAnnotationDefault new 
                            value:(self readAnnotationValueFor:something));
                default.
    endPos := inStream position.
    inStream position:startPos.
    annotationDefault bytes:(inStream next:len).
    self assert:inStream position = endPos
        description:'self readAnnotationValueFor: something is reading what it shouldn'.

    "Modified: / 28-02-2011 / 17:08:28 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 03-03-2011 / 23:06:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readAnnotationFor:something 
    | typeIndex  type  result  attrsCount |

    typeIndex := inStream nextUnsignedShortMSB:msb.
    type := constants at:typeIndex.
    attrsCount := inStream nextUnsignedShortMSB:msb.
    result := JavaAnnotation for:something.
    result name:type.
    attrsCount timesRepeat:
            [ | nameIndex  name  valueIndex  attr |

            nameIndex := inStream nextUnsignedShortMSB:msb.
            name := constants at:nameIndex.
            attr := self readAnnotationValueFor:something.
            attr name:name.
            result values at:attr name put:attr.
            AnnotationsVerbose 
                ifTrue:[ ('JAVA [INFO]: Reading annotation attribute: ' , name) infoPrintCR. ]. ].
    ^ result.

    "Created: / 17-12-2010 / 16:21:28 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 25-02-2011 / 12:25:36 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 27-07-2011 / 09:37:14 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readAnnotationValueFor:something 
    | tag  result |

    tag := (inStream nextByte) asCharacter.
    tag = $e 
        ifTrue:
            [ result := JavaAnnotationEnumValue for:something.
            result nameIndex:(inStream nextUnsignedShortMSB:msb).
            result valueIndex:(inStream nextUnsignedShortMSB:msb).
            AnnotationsVerbose 
                ifTrue:
                    [ ('JAVA [INFO]: Reading annotation enum value: ' , result name printString, ' -> ' 
                        , result value printString) infoPrintCR ].
            ^ result ].
    tag = $c 
        ifTrue:
            [ result := JavaAnnotationClassValue for:something.
            result classIndex:(inStream nextUnsignedShortMSB:msb).
            AnnotationsVerbose 
                ifTrue:
                    [ ('JAVA [INFO]: Reading annotation class value: ' , result name printString, ' -> ' 
                        , result value printString) infoPrintCR ].
            ^ result ].
    tag = $@ 
        ifTrue:
            [ result := JavaAnnotationNestedAnnotationValue for:something.
            result classIndex:(inStream nextUnsignedShortMSB:msb).
            AnnotationsVerbose 
                ifTrue:
                    [ ('JAVA [INFO]: Reading annotation nested annotation value: ' , result name printString
                        , ' -> ' , result value printString) 
                        infoPrintCR ].
            ^ result ].
    tag = $[ 
        ifTrue:
            [ result := JavaAnnotationArrayValue for:something.
            result count:(inStream nextUnsignedShortMSB:msb).
            AnnotationsVerbose 
                ifTrue:[ ('JAVA [INFO]: Reading annotation array value') infoPrintCR ].
            1 to:result count
                do:[:index | result values at:index put:(self readAnnotationValueFor:something) ].
            AnnotationsVerbose 
                ifTrue:
                    [ ('JAVA [INFO]: Finished reading annotation array value: ' 
                        , result value printString) infoPrintCR ].
            ^ result ].
    result := JavaAnnotationPrimitiveValue for:something.
    result valueIndex:(inStream nextUnsignedShortMSB:msb).
     AnnotationsVerbose 
                ifTrue:
                    [ ('JAVA [INFO]: Finished reading annotation primitive value: ' 
                             , result name printString , ' -> ' , result value printString) infoPrintCR ].
    ^ result.

    "Created: / 17-12-2010 / 16:44:14 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 28-02-2011 / 16:12:09 / Marcel Hlopko <hlopik@gmail.com>"
!

readAttribute:attributeName for:something 
    "/ implemented JAVA attributes
    
    (attributeName = 'ConstantValue') 
        ifTrue:
            [ self readConstantValueAttributeFor:something.
            ^ self. ].
    (attributeName = 'Code') 
        ifTrue:
            [ self readCodeAttributeFor:something.
            ^ self. ].
    (attributeName = 'Exceptions') 
        ifTrue:
            [ self readExceptionsAttributeFor:something.
            ^ self. ].
    (attributeName = 'InnerClasses') 
        ifTrue:
            [ self readInnerClassesAttributeFor:something.
            ^ self. ].
    (attributeName = 'EnclosingMethod') 
        ifTrue:
            [ self readEnclosingMethodAttributeFor:something.
            ^ self. ].
    (attributeName = 'LineNumberTable') 
        ifTrue:
            [ self readLineNumberTableAttributeFor:something.
            ^ self. ].
    (attributeName = 'LocalVariableTable') 
        ifTrue:
            [ self readLocalVariableTableAttributeFor:something.
            ^ self. ].
    (attributeName = 'LocalVariableTypeTable') 
        ifTrue:
            [ self readLocalVariableTypeTableAttributeFor:something.
            ^ self. ].
    (attributeName = 'SourceFile') 
        ifTrue:
            [ self readSourceFileAttributeFor:something.
            ^ self. ].
    (attributeName = 'SourceDebugExtension') 
        ifTrue:
            [ self readSourceDebugExtensionAttributeFor:something.
            ^ self. ].
    (attributeName = 'Synthetic') 
        ifTrue:
            [ self readSyntheticAttributeFor:something.
            ^ self. ].
    (attributeName = 'Signature') 
        ifTrue:
            [ self readSignatureAttributeFor:something.
            ^ self. ].
    (attributeName = 'Deprecated') 
        ifTrue:
            [ self readDeprecatedAttributeFor:something.
            ^ self. ].
    (attributeName = 'RuntimeVisibleAnnotations') 
        ifTrue:
            [ self readRuntimeAnnotationsAttributeFor:something visible:true.
            ^ self. ].
    (attributeName = 'RuntimeInvisibleAnnotations') 
        ifTrue:
            [  self readRuntimeAnnotationsAttributeFor:something visible:false.
            ^ self. ].
    (attributeName = 'RuntimeVisibleParameterAnnotations') 
        ifTrue:
            [ self readRuntimeParameterAnnotationsAttributeFor:something visible:true.
            ^ self. ].
    (attributeName = 'RuntimeInvisibleParameterAnnotations') 
        ifTrue:
            [ self readRuntimeParameterAnnotationsAttributeFor:something visible:false.
            ^ self. ].
    (attributeName = 'AnnotationDefault') 
        ifTrue:
            [ self readAnnotationDefaultAttributeFor:something.
            ^ self. ].
    
    "/ ignored JAVA attributes
    
    (attributeName = 'FastJavac1.0') 
        ifTrue:
            [ "/        ('JAVA [info]: unhandled attribute: ' , attributeName) infoPrintCR.
            self skipAttribute:attributeName.
            ^ self. ].
    (attributeName = 'AbsoluteSourcePath') 
        ifTrue:
            [ ('JAVA [info]: unhandled attribute: ' , attributeName) infoPrintCR.
            self skipAttribute:attributeName.
            ^ self. ].
    (attributeName startsWith:((Character value:13) asString , 'WARNING:')) 
        ifTrue:
            [ "/        ('JAVA [info]: unhandled attribute: ' , attributeName) infoPrintCR.
            self skipAttribute:attributeName.
            ^ self. ].
    (attributeName = 'StackMapTable') 
        ifTrue:
            [ "/        ('JAVA [info]: unhandled attribute: ' , attributeName) infoPrintCR.
            self readStackMapTableAttributeFor:something.
            ^ self. ].
    
    "/ implemented ST attributes
    
    (attributeName = 'STLiterals') 
        ifTrue:
            [ self readSTLiteralsAttributeFor:something.
            ^ self. ].
    (attributeName = 'ClassRevision') 
        ifTrue:
            [ self readSTClassRevisionAttributeFor:something.
            ^ self. ].
    (attributeName = 'ClassPackage') 
        ifTrue:
            [ self readSTClassPackageAttributeFor:something.
            ^ self. ].
    (attributeName = 'ClassCategory') 
        ifTrue:
            [ self readSTClassCategoryAttributeFor:something.
            ^ self. ].
    (attributeName = 'ClassVarNames') 
        ifTrue:
            [ self readSTClassVarNamesAttributeFor:something.
            ^ self. ].
    (attributeName = 'ClassInstVarNames') 
        ifTrue:
            [ self readSTClassInstVarNamesAttributeFor:something.
            ^ self. ].
    (attributeName = 'InstVarNames') 
        ifTrue:
            [ self readSTInstVarNamesAttributeFor:something.
            ^ self. ].
    (attributeName = 'STCode') 
        ifTrue:
            [ self readSTCodeAttributeFor:something.
            ^ self. ].
    (attributeName = 'MethodCategory') 
        ifTrue:
            [ self readSTMethodCategoryAttributeFor:something.
            ^ self. ].
    
    "/ unknown attributes
    
    ('JAVA [warning]: unrecognized attribute: ' , attributeName) infoPrintCR.
    self skipAttribute:attributeName.

    "Modified: / 03-12-1998 / 13:13:42 / cg"
    "Modified: / 25-02-2011 / 18:09:21 / Marcel Hlopko <hlopik@gmail.com>"
!

readAttributeFor:something
    |attribute_name_index attribute_name attribute_length attribute_info|

    Verbose ifTrue:[Transcript show:'attrib at pos: '; showCR:inStream position].

    attribute_name_index := inStream nextUnsignedShortMSB:msb.
    attribute_name_index == 0 ifTrue:[
        self halt.
        "/self skipAttribute:'unnamed'.
        ^ self.
    ].

    "/
    "/ UNDOC feature ?
    "/
    attribute_name_index > constants size ifTrue:[
        attribute_name_index == 16rb700 ifTrue:[
            self halt.
        ]
    ].

    attribute_name := constants at:attribute_name_index.

    Verbose ifTrue:[Transcript show:'attrib name: '; showCR:attribute_name].

    self readAttribute:attribute_name for:something.

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
    "

    "Created: / 15-04-1996 / 15:40:17 / cg"
    "Modified: / 09-04-1998 / 18:13:34 / cg"
    "Modified: / 19-10-2010 / 21:43:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readAttributesFor:something
    |attributes_count|

    attributes_count := inStream nextUnsignedShortMSB:msb.

    1 to:attributes_count do:[:i |
	self readAttributeFor:something.
    ].

    "Modified: 15.4.1996 / 15:33:28 / cg"
    "Created: 15.4.1996 / 15:40:17 / cg"
!

readDeprecatedAttributeFor:aJavaMethodWithHandler

    self skipAttribute:'Deprecated'.
    ^self

    "Created: / 18-10-2010 / 22:26:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readEnclosingMethodAttributeFor:something
"/        ('JAVA [info]: unhandled attribute: EnclosingMethod') infoPrintCR.
        self skipAttribute:'EnclosingMethod'.
!

readInnerClassesAttributeFor:something
"/        ('JAVA [info]: unhandled attribute: InnerClasses') infoPrintCR.
        self skipAttribute:'InnerClasses'.
!

readLocalVariableTypeTableAttributeFor:something
"/        ('JAVA [info]: unhandled attribute: LocalVariableTypeTable') infoPrintCR.
        self skipAttribute:'LocalVariableTypeTable'.
!

readRuntimeAnnotationsAttributeFor: something visible: visible 
    | length  annotationsCount  annotations  rawAnnotations  startPos  endPos |

    self assert: inStream isPositionable
        message: '.class file stream must be positionable'.
    length := inStream nextUnsignedLongMSB: msb.
    startPos := inStream position.
    annotationsCount := inStream nextUnsignedShortMSB: msb.
    annotationsCount = 0 ifTrue: [ ^ nil ].
    annotations := visible ifTrue: [something ensureHasAnnotations ensureRuntimeVisible] ifFalse: [something ensureHasAnnotations ensureRuntimeInvisible].
    annotationsCount timesRepeat: 
            [ | currentAnnotation |

            currentAnnotation := self readAnnotationFor: something.
            annotations at: currentAnnotation name put: currentAnnotation. ].
     "Cut raw annotations as required by getRawAnnotations()"
    endPos := inStream position.
    inStream position: startPos.
    rawAnnotations := inStream next: length.
    inStream position ~= endPos 
        ifTrue: [ self halt: 'annotations are probably reading what they shouldnt' ].
    annotations rawAnnotations: rawAnnotations.

    "Modified: / 07-01-2011 / 22:00:07 / Jan Kurs <kurs.jan@post.cz>"
    "Modified: / 25-02-2011 / 18:45:58 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 03-03-2011 / 23:01:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 16-03-2011 / 16:57:03 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readRuntimeParameterAnnotationsAttributeFor: javaMethod visible: visible 
    | length  paramsCount  annotationsCount rawAnnotations  startPos  endPos |

    self assert: inStream isPositionable
        message: '.class file stream must be positionable'.
    length := inStream nextUnsignedLongMSB: msb.
    startPos := inStream position.
    paramsCount := inStream nextByte.
    paramsCount = 0 ifTrue: [ ^ nil ].
    1 to: paramsCount
        do: 
            [:paramIndex | 
            annotationsCount := inStream nextUnsignedShortMSB: msb.
            annotationsCount > 0 
                ifTrue: 
                    [ | annotations |
                    annotations := visible 
                                ifTrue: 
                                    [ javaMethod ensureHasAnnotations ensureVisibleParameterAnnotationsAt: paramIndex ]
                                ifFalse: 
                                    [javaMethod ensureHasAnnotations ensureInvisibleParameterAnnotationsAt: paramIndex ].
                    annotationsCount timesRepeat: 
                    [ | annotation |

                    annotation := self readAnnotationFor: javaMethod.
                    annotations at: (annotation name) put: annotation. ] ]].
    endPos := inStream position.
    rawAnnotations := inStream position: startPos.
    rawAnnotations := inStream next: length.
    inStream position ~= endPos 
        ifTrue: [ self halt: 'annotations are probably reading what they shouldnt' ].
    javaMethod annotations rawAnnotations: rawAnnotations.

    "Modified: / 28-02-2011 / 17:05:47 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 16-03-2011 / 17:26:42 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readSignatureAttributeFor:something

    |attribute_length signature_index signature|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    signature_index := inStream nextUnsignedShortMSB:msb.
    signature := constants at:signature_index.

    something setSignature: signature.

    "Modified: / 13-08-2011 / 00:28:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readSourceDebugExtensionAttributeFor:something
"/        ('JAVA [info]: unhandled attribute: SourceDebugExtension') infoPrintCR.
        self skipAttribute:'SourceDebugExtension'.
!

readSourceFileAttributeFor:aClass
    |attribute_length sourceFile_index sourceFile|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    sourceFile_index := inStream nextUnsignedShortMSB:msb.
    sourceFile := constants at:sourceFile_index.

    aClass isJavaClass ifTrue:[
        aClass setSourceFile:sourceFile.
    ] ifFalse:[
        aClass setClassFilename:sourceFile
    ].

    Verbose ifTrue:[Transcript show:'sourceFile: '; showCR:sourceFile].
    ^ true

    "
     JavaClassReader loadFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader loadFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'
     JavaClassReader loadFile:'foo.cls'
    "

    "Created: / 15.4.1996 / 15:40:17 / cg"
    "Modified: / 12.5.1998 / 22:01:07 / cg"
!

readStackMapTableAttributeFor:something 
"/        ('JAVA [info]: unhandled attribute: StackMapTable') infoPrintCR.
    self skipAttribute:'StackMapTable'.

    "Created: / 09-02-2011 / 01:19:20 / Marcel Hlopko <hlopik@gmail.com>"
!

readSyntheticAttributeFor:something
"/        ('JAVA [info]: unhandled attribute: Synthetic') infoPrintCR.
        self skipAttribute:'Synthetic'.
!

skipAttribute:attributeName
    "dont know about this attribute - skip it here"

    |attribute_length attribute_info|

    attribute_length := inStream nextUnsignedLongMSB:msb.
    attribute_info := ByteArray new:(attribute_length).
    inStream nextBytes:attribute_length into:attribute_info startingAt:1.

    Verbose ifTrue:[Transcript show:'skipped '; show:attributeName; showCR:'-attribute'].

    "Created: / 9.4.1998 / 18:12:46 / cg"
    "Modified: / 9.4.1998 / 18:13:20 / cg"
! !

!JavaClassReader methodsFor:'file reading - attributes-ST'!

readSTClassCategoryAttributeFor:aClass
    |attribute_length categoryString_index categoryString|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    categoryString_index := inStream nextUnsignedShortMSB:msb.
    categoryString := constants at:categoryString_index.

    aClass category:categoryString.

    Verbose ifTrue:[Transcript show:'categoryString: '; showCR:categoryString].
    ^ true

    "
     JavaClassReader loadFile:'foo.cls'
    "

    "Created: / 9.5.1998 / 02:33:13 / cg"
    "Modified: / 9.5.1998 / 02:36:55 / cg"
!

readSTClassInstVarNamesAttributeFor:aClass
    |attribute_length nameString_index nameString|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    nameString_index := inStream nextUnsignedShortMSB:msb.
    nameString := constants at:nameString_index.

    aClass class instanceVariableString:nameString.

    Verbose ifTrue:[Transcript show:'nameString: '; showCR:nameString].
    ^ true

    "
     JavaClassReader loadFile:'foo.cls'
    "

    "Modified: / 12.5.1998 / 22:18:03 / cg"
    "Created: / 12.5.1998 / 22:18:24 / cg"
!

readSTClassPackageAttributeFor:aClass
    |attribute_length packageString_index packageString|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    packageString_index := inStream nextUnsignedShortMSB:msb.
    packageString := constants at:packageString_index.

    aClass package:packageString asSymbol.

    Verbose ifTrue:[Transcript show:'packageString: '; showCR:packageString].
    ^ true

    "
     JavaClassReader loadFile:'foo.cls'
    "

    "Modified: / 9.5.1998 / 02:32:38 / cg"
    "Created: / 9.5.1998 / 02:33:44 / cg"
!

readSTClassRevisionAttributeFor:aClass
    |attribute_length revisionString_index revisionString|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    revisionString_index := inStream nextUnsignedShortMSB:msb.
    revisionString := constants at:revisionString_index.

    aClass setBinaryRevision:revisionString.

    Verbose ifTrue:[Transcript show:'revisionString: '; showCR:revisionString].
    ^ true

    "
     JavaClassReader loadFile:'foo.cls'
    "

    "Created: / 9.5.1998 / 02:33:13 / cg"
    "Modified: / 9.5.1998 / 02:35:01 / cg"
!

readSTClassVarNamesAttributeFor:aClass
    |attribute_length nameString_index nameString|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    nameString_index := inStream nextUnsignedShortMSB:msb.
    nameString := constants at:nameString_index.

    aClass classVariableString:nameString.

    Verbose ifTrue:[Transcript show:'nameString: '; showCR:nameString].
    ^ true

    "
     JavaClassReader loadFile:'foo.cls'
    "

    "Created: / 9.5.1998 / 02:33:13 / cg"
    "Modified: / 12.5.1998 / 22:18:03 / cg"
!

readSTInstVarNamesAttributeFor:aClass
    |attribute_length nameString_index nameString|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    nameString_index := inStream nextUnsignedShortMSB:msb.
    nameString := constants at:nameString_index.

    aClass setInstanceVariableString:nameString.

    Verbose ifTrue:[Transcript show:'nameString: '; showCR:nameString].
    ^ true

    "
     JavaClassReader loadFile:'foo.cls'
    "

    "Created: / 12.5.1998 / 22:18:14 / cg"
    "Modified: / 12.5.1998 / 22:21:10 / cg"
! !

!JavaClassReader methodsFor:'file reading - constants'!

readConstant
    |tag constReader const|


    constNeeds2Slots := false.

    "/
    "/ get tag
    "/
    tag := inStream nextByte.
    Verbose ifTrue:[Transcript show:'tag = '; showCR:tag].

    tag >= 250 ifTrue:[
        constReader := #(
                        "/ ST types
                        readConstant_ST_Large           "/ 249
                        readConstant_ST_Special         "/ 250
                        readConstant_ST_Character       "/ 251
                        readConstant_ST_ByteArray       "/ 252
                        readConstant_ST_Array           "/ 253
                        readConstant_ST_Symbol          "/ 254
                        readConstant_ST_Reserved        "/ 255
                    ) at:tag-249+1.
    ] ifFalse:[
        constReader := #(
                        "/ JAVA types
                        readConstant_Utf8               "/ 1  - now called Utf8
                        readConstant_Unicode            "/ 2
                        readConstant_Integer            "/ 3
                        readConstant_Float              "/ 4
                        readConstant_Long               "/ 5
                        readConstant_Double             "/ 6
                        readConstant_Class              "/ 7
                        readConstant_String             "/ 8
                        readConstant_Fieldref           "/ 9
                        readConstant_Methodref          "/ 10
                        readConstant_InterfaceMethodref "/ 11
                        readConstant_NameAndType        "/ 12
                    ) at:tag ifAbsent:[#readConstant_Undef].
    ].
    ^ self perform:constReader.

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
    "

    "Created: / 15.4.1996 / 15:46:32 / cg"
    "Modified: / 9.5.1998 / 01:26:05 / cg"
!

readConstantPool
    | constantPoolSize  const |

    "/
    "/ get constant pool
    "/
    constantPoolSize := inStream nextUnsignedShortMSB: msb.
    self info: 'constantPoolSize = ' , constantPoolSize printString.
    constants := JavaConstantPool new: constantPoolSize - 1.
    constSlot := 1.
    [ constSlot < constantPoolSize ] whileTrue: [
            self info: 'const slot: ' , constSlot printString.
            const := self readConstant.
            constants at: constSlot put: const.
            
            "/ long & double consts take 2 slots
            "/ (only first is used)
            
            constNeeds2Slots 
                ifTrue: [ constSlot := constSlot + 2. ]
                ifFalse: [ constSlot := constSlot + 1. ]].
    constSlot := -1.
    
    1 to: constantPoolSize - 1
        do: 
            [:i | 
            | const  value |

            const := constants at: i.
            const ifNotNil: 
                    [ "/ kludge for 2-slot constants (which only take 1 slot in ST/X)
                    (const isKindOf: JavaUnresolvedConstant) 
                        ifTrue: 
                            [ value := const preResolve.
                            value ~~ const ifTrue: [ constants at: i put: value. ] ] ] ].

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'"

    "Modified: / 07-05-1998 / 11:44:06 / cg"
    "Created: / 13-05-2011 / 16:52:54 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_Asciz
    | len  string |


    len := inStream nextUnsignedShortMSB: msb.
    string := String new: len.
    inStream 
        nextBytes: len
        into: string
        startingAt: 1.
    Verbose 
        ifTrue: 
            [ Transcript
                show: 'asciz; string= ';
                showCR: string ].
    ^ string

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'"

    "Created: / 15-04-1996 / 15:15:35 / cg"
    "Modified: / 15-04-1996 / 16:33:45 / cg"
    "Modified: / 13-05-2011 / 17:31:39 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_Class
    | nameIndex |

    nameIndex := inStream nextUnsignedShortMSB: msb.
    ((constants at: nameIndex) isNil) 
        ifTrue: 
            [ self info: ('reading class; index=' , nameIndex printString , ' name=' 
                        , (constants at: nameIndex) printString) ]
        ifFalse: [ self info: ('reading class; index= ' , nameIndex printString) ].
    ^ JavaClassRef2 in: constants withNameAt: nameIndex.

    "Modified: / 18-05-2011 / 18:21:16 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_Double
    |high low aFloat bytes|

"/ new code - to be tested
"/    bytes := ByteArray new:8.
"/
"/    inStream nextBytes:8 into:bytes startingAt:1.
"/    msb ~~ UninterpretedBytes isBigEndian ifTrue:[
"/        bytes reverse
"/    ].
"/    aFloat := bytes doubleAt:1.

"/ old code

    high := inStream nextUnsignedLongMSB:msb.
    low := inStream nextUnsignedLongMSB:msb.

    aFloat := Float new.
    UninterpretedBytes isBigEndian ifTrue:[
        aFloat basicAt:1 put:((high bitShift:-24) bitAnd:16rFF).
        aFloat basicAt:2 put:((high bitShift:-16) bitAnd:16rFF).
        aFloat basicAt:3 put:((high bitShift:-8) bitAnd:16rFF).
        aFloat basicAt:4 put:(high bitAnd:16rFF).
        aFloat basicAt:5 put:((low bitShift:-24) bitAnd:16rFF).
        aFloat basicAt:6 put:((low bitShift:-16) bitAnd:16rFF).
        aFloat basicAt:7 put:((low bitShift:-8) bitAnd:16rFF).
        aFloat basicAt:8 put:(low bitAnd:16rFF).
    ] ifFalse:[
        aFloat basicAt:1 put:(low bitAnd:16rFF).
        aFloat basicAt:2 put:((low bitShift:-8) bitAnd:16rFF).
        aFloat basicAt:3 put:((low bitShift:-16) bitAnd:16rFF).
        aFloat basicAt:4 put:((low bitShift:-24) bitAnd:16rFF).
        aFloat basicAt:5 put:(high bitAnd:16rFF).
        aFloat basicAt:6 put:((high bitShift:-8) bitAnd:16rFF).
        aFloat basicAt:7 put:((high bitShift:-16) bitAnd:16rFF).
        aFloat basicAt:8 put:((high bitShift:-24) bitAnd:16rFF).
    ].

    constNeeds2Slots := true.

    Verbose ifTrue:[Transcript show:'double; value= ';     showCR:aFloat].
    ^ aFloat

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'
    "

    "Created: / 15.4.1996 / 16:34:42 / cg"
    "Modified: / 8.5.1998 / 22:06:07 / cg"
!

readConstant_Fieldref    
    "incrementally changing resolving logic, fields will come later"

    | classIndex  nameAndTypeIndex |

    classIndex := inStream nextUnsignedShortMSB: msb.
    nameAndTypeIndex := inStream nextUnsignedShortMSB: msb.
    self 
        info: 'reading fieldref; classindex=' , classIndex printString 
                , ' nameAndTypeIndex=' , nameAndTypeIndex printString.
    ^ JavaFieldRef2 
        in: constants
        withNameAndTypeAt: nameAndTypeIndex
        andClassAt: classIndex.

    "Modified: / 15-05-2011 / 14:20:23 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_Float
    |b1 b2 b3 b4 aFloat bytes|

"/ new code - to be tested ...
"/
"/    bytes := ByteArray new:4.
"/    inStream nextBytes:4 into:bytes startingAt:1.
"/    msb ~~ UninterpretedBytes isBigEndian ifTrue:[
"/        bytes reverse
"/    ].
"/    aFloat := bytes floatAt:1.
"/    Verbose ifTrue:[Transcript show:'float; value= ';     showCR:aFloat].
"/    ^ aFloat.

"/ old code

    aFloat := ShortFloat basicNew.

    b1 := inStream nextByte.
    b2 := inStream nextByte.
    b3 := inStream nextByte.
    b4 := inStream nextByte.

    UninterpretedBytes isBigEndian ifTrue:[
        aFloat basicAt:1 put:b1.
        aFloat basicAt:2 put:b2.
        aFloat basicAt:3 put:b3.
        aFloat basicAt:4 put:b4.
    ] ifFalse:[
        aFloat basicAt:4 put:b1.
        aFloat basicAt:3 put:b2.
        aFloat basicAt:2 put:b3.
        aFloat basicAt:1 put:b4.
    ].
    Verbose ifTrue:[Transcript show:'float; value= ';     showCR:aFloat].
    ^ aFloat

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'
    "

    "Created: / 15.4.1996 / 16:34:42 / cg"
    "Modified: / 10.11.1998 / 22:04:59 / cg"
!

readConstant_Integer
    |value|

    value := inStream nextLongMSB:msb.

    Verbose ifTrue:[Transcript show:'integer; value= ';     showCR:value].

    ^ value

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'
    "

    "Modified: 15.4.1996 / 15:42:16 / cg"
    "Created: 15.4.1996 / 16:34:42 / cg"
!

readConstant_InterfaceMethodref
    | classIndex  nameAndTypeIndex  |

    classIndex := inStream nextUnsignedShortMSB: msb.
    nameAndTypeIndex := inStream nextUnsignedShortMSB: msb.    
    self 
        info: 'reading interface methodref; classindex=' , classIndex printString                 
                , ' nameAndTypeIndex=' , nameAndTypeIndex printString.                
    ^ JavaInterfaceMethodRef2 
        in: constants
        withNameAndTypeAt: nameAndTypeIndex
        andClassAt: classIndex.

    "Modified: / 12-05-2011 / 18:57:47 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_Long
    |high low value|

    high := inStream nextUnsignedLongMSB:msb.
    low := inStream nextUnsignedLongMSB:msb.

    value := (high bitShift:32) bitOr:low.
    (high bitTest:16r80000000) ifTrue:[
	value := value - 16r10000000000000000.
    ].
    constNeeds2Slots := true.

    Verbose ifTrue:[Transcript show:'long; value= ';     showCR:value].
    ^ value

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'
    "

    "Modified: 15.4.1996 / 15:42:16 / cg"
    "Created: 15.4.1996 / 16:34:42 / cg"
!

readConstant_Methodref
    | classIndex  nameAndTypeIndex   |

    classIndex := inStream nextUnsignedShortMSB: msb.
    nameAndTypeIndex := inStream nextUnsignedShortMSB: msb.   
    self 
        info: 'reading methodref; classindex=' , classIndex printString , ' nameAndTypeIndex=' 
                , nameAndTypeIndex printString.
    ^ JavaMethodRef2 
        in: constants
        withNameAndTypeAt: nameAndTypeIndex
        andClassAt: classIndex.

    "Modified: / 15-05-2011 / 14:20:38 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_NameAndType
    | nameIndex  descriptorIndex |

    nameIndex := inStream nextUnsignedShortMSB: msb.
    descriptorIndex := inStream nextUnsignedShortMSB: msb.
    self 
        info: 'reading nameAndType; nameindex=' , nameIndex printString 
                , ' descriptorIndex= ' , descriptorIndex printString.
    ^JavaNameAndType2 
                in: constants
                withNameAt: nameIndex
                andDescriptorAt: descriptorIndex.

    "Modified: / 10-05-2011 / 17:09:47 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_String
    | string_index  chars  jString |

    string_index := inStream nextUnsignedShortMSB: msb.
    Verbose 
        ifTrue: 
            [ Transcript
                show: 'string; index= ';
                showCR: string_index ].
    
    "/ resolve here if possible
    
    string_index < constSlot 
        ifTrue: 
            [ Java java_lang_String notNil 
                ifTrue: 
                    [ chars := (constants at: string_index).
                    chars isString ifFalse: [ self halt: 'should not happen' ].
                    jString := JavaVM javaStringObjectForString:chars interned:true.
                    ^ jString. ] ].
    ^ JavaUnresolvedStringConstant 
        pool: constants
        poolIndex: constSlot
        stringIndex: string_index

    "
     Verbose := true.
     JavaClassReader readFile:'/phys/ibm3/java/lib/java/lang/System.class'"

    "Created: / 15-04-1996 / 15:20:33 / cg"
    "Modified: / 07-05-1998 / 11:42:45 / cg"
    "Modified: / 13-05-2011 / 17:31:54 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 10-08-2011 / 23:25:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readConstant_Unicode
    | len  string  ascii |

    len := inStream nextUnsignedShortMSB: msb.
    string := TwoByteString new: len.
    1 to: len
        do: 
            [:idx | 
            ascii := inStream nextUnsignedShortMSB: msb.
            string at: idx put: (Character value: ascii). ].
    Verbose 
        ifTrue: 
            [ Transcript
                show: 'asciz; unicodeString= ';
                showCR: string ].
    ^ string

    "Modified: / 13-05-2011 / 17:31:44 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_Utf8
    | len  bytes  string |

    len := inStream nextUnsignedShortMSB: msb.
    bytes := ByteArray new: len.
    inStream 
        nextBytes: len
        into: bytes
        startingAt: 1.
    string := CharacterArray fromJavaUTF8Bytes: bytes.
    Verbose 
        ifTrue: 
            [ Transcript
                show: 'asciz; string= ';
                showCR: string ].
    ^ string

    "Modified: / 19-10-2010 / 12:38:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 13-05-2011 / 17:31:48 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaClassReader methodsFor:'file reading - constants-ST'!

readConstant_ST_Array
    |aSize arr|

    aSize := inStream nextUnsignedShortMSB:msb.
    arr := Array new:aSize.

    1 to:aSize do:[:i |
        |element_index element|

        element_index := inStream nextUnsignedShortMSB:msb.
        arr at:i put:element_index.
    ].
    Verbose ifTrue:[Transcript show:'array; size= ';     showCR:aSize].

    ^ JavaUnresolvedSTArrayConstant 
                pool:constants
                poolIndex:constSlot
                array:arr

    "Created: / 7.5.1998 / 11:47:01 / cg"
    "Modified: / 9.5.1998 / 00:25:34 / cg"
!

readConstant_ST_ByteArray
    |aSize arr|

    aSize := inStream nextUnsignedShortMSB:msb.
    arr := ByteArray new:aSize.

    1 to:aSize do:[:i |
        |element_index|

        arr at:i put:(inStream nextByte).
    ].
    Verbose ifTrue:[Transcript show:'byteArray; size= ';     showCR:aSize].

    ^ arr

    "Created: / 7.5.1998 / 11:47:12 / cg"
!

readConstant_ST_Character
    |ascii|

    ascii := inStream nextUnsignedShortMSB:msb.

    Verbose ifTrue:[Transcript show:'char; ascii= '; showCR:ascii].
    ^ Character value:ascii

    "Created: / 7.5.1998 / 11:48:12 / cg"
!

readConstant_ST_Special
    |type|

    type := inStream nextUnsignedShortMSB:msb.
    ^ #(
        nil
        true
        false
     ) at:(type + 1)

    "Created: / 8.5.1998 / 23:06:56 / cg"
    "Modified: / 9.5.1998 / 00:40:14 / cg"
!

readConstant_ST_String
    | tag  string_index  chars |


    string_index := inStream nextUnsignedShortMSB: msb.
    Verbose 
        ifTrue: 
            [ Transcript
                show: 'string; index= ';
                showCR: string_index ].
    
    "/ resolve here if possible
    
    string_index < constSlot 
        ifTrue: 
            [ chars := (constants at: string_index).
            ^ chars ].
    ^ JavaUnresolvedSTStringConstant 
        pool: constants
        poolIndex: constSlot
        stringIndex: string_index

    "Created: / 07-05-1998 / 11:49:55 / cg"
    "Modified: / 13-05-2011 / 17:32:03 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

readConstant_ST_Symbol
    | tag  string_index  chars |


    string_index := inStream nextUnsignedShortMSB: msb.
    Verbose 
        ifTrue: 
            [ Transcript
                show: 'symbol; index= ';
                showCR: string_index ].
    
    "/ resolve here if possible
    
    string_index < constSlot 
        ifTrue: 
            [ chars := (constants at: string_index).
            chars isString ifFalse: [ self halt: 'should not happen' ].
            ^ chars asSymbol ].
    ^ JavaUnresolvedSTSymbolConstant 
        pool: constants
        poolIndex: constSlot
        stringIndex: string_index

    "Modified: / 07-05-1998 / 11:48:28 / cg"
    "Modified: / 13-05-2011 / 17:32:09 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaClassReader methodsFor:'file reading - fields'!

readConstantValueAttributeFor:aField
    |attribute_length constantvalue_index constantValue|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    constantvalue_index := inStream nextUnsignedShortMSB:msb.
    constantValue := constants at:constantvalue_index.

    aField constantValue:constantValue.

    Verbose ifTrue:[Transcript show:'constantValue: '; showCR:constantValue].
    ^ true

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'
    "

    "Modified: 15.4.1996 / 15:33:28 / cg"
    "Created: 15.4.1996 / 15:40:17 / cg"
!

readFieldInfofield
    | access_flags  name_index  descriptor_index  attributes_count  field |

    access_flags := inStream nextUnsignedShortMSB: msb.
    name_index := inStream nextUnsignedShortMSB: msb.
    descriptor_index := inStream nextUnsignedShortMSB: msb.
    field := JavaField new.
    field setAccessFlags: access_flags.
    field setName: (constants at: name_index) asSymbol.
    field setDescriptor: (constants at: descriptor_index) asSymbol.
    field setConstantPool: constants.
    attributes_count := inStream nextUnsignedShortMSB: msb.
    Verbose 
        ifTrue: 
            [ Transcript
                show: '  field name: ';
                show: (constants at: name_index);
                show: ' access: ';
                show: access_flags;
                show: ' attrib_cnt: ';
                showCR: attributes_count ].
    1 to: attributes_count do: [:i | self readAttributeFor: field. ].
    ^ field.

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'"

    "Created: / 15-04-1996 / 15:38:43 / cg"
    "Modified: / 15-10-1998 / 10:38:01 / cg"
    "Modified: / 17-12-2010 / 18:44:30 / Marcel Hlopko <hlopik@gmail.com>"
    "Modified: / 18-05-2011 / 14:11:37 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 14-08-2011 / 19:40:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readFieldInfofields
    |nFields fields|

    "/
    "/ get fieldInfos
    "/
    nFields := inStream nextUnsignedShortMSB:msb.
    Verbose ifTrue:[Transcript show:'fieldsCount = '; showCR:nFields].

    fields := Array new:nFields.

    1 to:nFields do:[:i |
	Verbose ifTrue:[Transcript show:'field: '; showCR:i].
	fields at:i put:(self readFieldInfofield)
    ].
    ^ fields

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
    "

    "Created: 15.4.1996 / 15:34:41 / cg"
    "Modified: 15.4.1996 / 15:35:28 / cg"
! !

!JavaClassReader methodsFor:'file reading - interfaces'!

readInterfaces
    |interfacesCount interface_index interface interfaces|

    "/
    "/ get interfaces
    "/
    interfacesCount := inStream nextUnsignedShortMSB:msb.
    Verbose ifTrue:[Transcript show:'interfacesCount = '; showCR:interfacesCount].

    interfaces := Array new:interfacesCount.

    1 to:interfacesCount do:[:i |
	Verbose ifTrue:[Transcript show:'interface: '; showCR:i].
	interface_index := inStream nextUnsignedShortMSB:msb.
	interface := constants at:interface_index.

	interfaces at:i put:interface.
    ].
    ^ interfaces

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
    "

    "Created: 15.4.1996 / 15:31:59 / cg"
    "Modified: 15.4.1996 / 15:33:28 / cg"
! !

!JavaClassReader methodsFor:'file reading - methods'!

readCodeAttributeFor:aJavaMethod
    |attribute_length max_stack max_locals code_length code
     exception_table_length exception_table unknown1 unknown2|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    Verbose ifTrue:[Transcript show:'code_attribute_length: 0x'; showCR:(attribute_length printStringRadix:16)].

    ((minorVsn > 2) or:[majorVsn > 45]) ifTrue:[
        "/ should be:
        max_stack := inStream nextUnsignedShortMSB:msb.
        max_locals := inStream nextUnsignedShortMSB:msb.
        code_length := inStream nextUnsignedLongMSB:msb.

"/        unknown1 := inStream nextByte.
"/        max_stack := inStream nextByte.
"/        max_locals := inStream nextUnsignedShortMSB:msb.
"/        unknown2 := inStream nextUnsignedShortMSB:msb.
"/        code_length := inStream nextUnsignedShortMSB:msb.
"/        Verbose ifTrue:[Transcript show:'?1: '; showCR:unknown1].
"/        Verbose ifTrue:[Transcript show:'?2: '; showCR:unknown2].
    ] ifFalse:[
        max_stack := inStream nextByte.
        max_locals := inStream nextByte.
        code_length := inStream nextUnsignedShortMSB:msb.
    ].

    Verbose ifTrue:[
        Transcript show:'code_length: '; showCR:(code_length printStringRadix:16).
        Transcript show:'code at pos: '; showCR:inStream position
    ].

    code_length ~~ 0 ifTrue:[
        code := ByteArray new:code_length.
        inStream nextBytes:code_length into:code startingAt:1.
    ].
    Verbose ifTrue:[Transcript show:'method code: '; showCR:code.].

    exception_table_length := inStream nextUnsignedShortMSB:msb.
    Verbose ifTrue:[Transcript show:'exception_table_length: '; showCR:(exception_table_length printStringRadix:16)].
    exception_table_length ~~ 0 ifTrue:[
        Verbose ifTrue:[Transcript show:'exceptionTable length:'; showCR:exception_table_length.].

        exception_table := Array new:exception_table_length.
        1 to:exception_table_length do:[:i |
            |start_pc end_pc handler_pc catch_type|

            start_pc := inStream nextUnsignedShortMSB:msb.
            end_pc := inStream nextUnsignedShortMSB:msb.
            handler_pc := inStream nextUnsignedShortMSB:msb.
            catch_type := inStream nextUnsignedShortMSB:msb.
            catch_type ~= 0 ifTrue:[
                catch_type := constants at:catch_type.
            ].
            exception_table at:i put:(JavaExceptionTableEntry
                                            startPC:start_pc
                                            endPC:end_pc
                                            handlerPC:handler_pc
                                            catchType:catch_type).
        ].
        aJavaMethod setExceptionHandlerTable:exception_table.
    ].

    aJavaMethod 
        setCode:code 
        maxStack:max_stack 
        maxLocals:max_locals 
        u1:unknown1 
        u2:unknown2.

    self readAttributesFor:aJavaMethod.
    ^ true

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/Alignable.class'
    "

    "Created: / 15-04-1996 / 15:40:17 / cg"
    "Modified: / 16-05-1998 / 01:39:42 / cg"
    "Modified: / 17-12-2010 / 00:24:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readExceptionsAttributeFor:aJavaMethod
    |attribute_length exception_table_length exception_table|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    exception_table_length := inStream nextUnsignedShortMSB:msb.
    exception_table_length ~~ 0 ifTrue:[
	exception_table := Array new:exception_table_length.
	1 to:exception_table_length do:[:i |
	    |idx ex|

	    idx := inStream nextUnsignedShortMSB:msb.
	    ex := constants at:idx.
	    exception_table at:i put:ex.
	].
    ].

    Verbose ifTrue:[Transcript showCR:'method has an exceptionTable'].

    aJavaMethod setExceptionTable:exception_table.
    ^ true

    "Modified: 15.4.1996 / 15:33:28 / cg"
    "Created: 15.4.1996 / 15:40:17 / cg"
!

readLineNumberTableAttributeFor:aJavaMethod
    |attribute_length line_number_table_length line_number_table|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    line_number_table_length := inStream nextUnsignedShortMSB:msb.
    line_number_table_length ~~ 0 ifTrue:[
        line_number_table := Array new:line_number_table_length.
        1 to:line_number_table_length do:[:i |
            |start_pc line_number|

            start_pc := inStream nextUnsignedShortMSB:msb.
            line_number := inStream nextUnsignedShortMSB:msb.
            line_number_table at:i put:(start_pc -> line_number).
        ].
        Verbose ifTrue:[Transcript showCR:'method has a lineNumberTable'].

        aJavaMethod setLineNumberTable:line_number_table.
    ].

    ^ true

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/java/lang/Boolean.class'
    "

    "Created: / 15.4.1996 / 15:40:17 / cg"
    "Modified: / 7.4.1998 / 19:08:42 / cg"
!

readLocalVariableTableAttributeFor:aJavaMethod
    |attribute_length local_variable_table_length local_variable_table|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    local_variable_table_length := inStream nextUnsignedShortMSB:msb.
    local_variable_table_length ~~ 0 ifTrue:[
	local_variable_table := JavaLocalVariableTable new:local_variable_table_length.
	1 to:local_variable_table_length do:[:i |
	    |start_pc length name_index sig_index slot name signature|

	    start_pc := inStream nextUnsignedShortMSB:msb.
	    length := inStream nextUnsignedShortMSB:msb.
	    name_index := inStream nextUnsignedShortMSB:msb.
	    name := constants at:name_index.
	    sig_index := inStream nextUnsignedShortMSB:msb.
	    signature := constants at:sig_index.
	    slot := inStream nextUnsignedShortMSB:msb.

	    local_variable_table at:i put:(JavaLocalVariableTableEntry new 
						startPC:start_pc 
						length:length
						name:name
						signature:signature
						slot:slot)
	].
    ].

    Verbose ifTrue:[Transcript showCR:'method has a localvariableTable'].

    aJavaMethod setLocalVariableTable:local_variable_table.
    ^ true

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/java/lang/Boolean.class'
    "

    "Modified: 15.4.1996 / 15:33:28 / cg"
    "Created: 15.4.1996 / 15:40:17 / cg"
!

readMethodFor:aClass
    |m access_flags name_index name descriptor_index descriptor
     tooManyArgs|

    "/
    "/ get a method
    "/
    access_flags := inStream nextUnsignedShortMSB:msb.
    name_index := inStream nextUnsignedShortMSB:msb.
    descriptor_index := inStream nextUnsignedShortMSB:msb.

    name := constants at:name_index.
    descriptor := constants at:descriptor_index.

    Verbose ifTrue:[
        Transcript show:'method name:'; showCR:name.
        Transcript show:'descriptor:'; showCR:descriptor.
    ].

    aClass isJavaClass ifTrue:[
        (access_flags bitAnd:JavaMethod A_NATIVE) ~~ 0 ifTrue:[
            m := JavaNativeMethod new.
        ] ifFalse:[
            m := JavaMethodWithHandler new.
        ].
        m setAccessFlags:access_flags.
        tooManyArgs := false.
        ArgumentError handle:[:ex |
            'JAVA: ***** java method has too many arguments - will fail to execute' infoPrintCR.
            tooManyArgs := true.
            ex proceed.
        ] do:[
            m setName:name descriptor:descriptor.
        ].
        m setJavaClass:aClass.

        self readAttributesFor:m.

        tooManyArgs ifTrue:[
            m code:nil.
            m byteCode:nil.
        ].
        (m exceptionHandlerTable isNil) ifTrue:[
            m isNative ifFalse:[
                m getExceptionTable isNil ifTrue:[
                    m := JavaMethod fromMethod:m
                ] ifFalse:[
                    m := JavaMethodWithException fromMethod:m
                ]
            ]
        ] ifFalse:[
            m setAccessFlags:(m accessFlags bitOr:JavaMethod A_HASHANDLER)
        ].
        aClass addMethod:m name:name signature:descriptor.
    ] ifFalse:[
        m := Method new.
        self readAttributesFor:m.
        (access_flags bitTest:JavaMethod A_STATIC) ifTrue:[
            aClass class primAddSelector:name asSymbol withMethod:m.
        ] ifFalse:[
            aClass primAddSelector:name asSymbol withMethod:m.
        ]
    ].

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
    "

    "Created: / 15-04-1996 / 16:48:49 / cg"
    "Modified: / 25-09-1999 / 23:16:25 / cg"
    "Modified: / 14-08-2011 / 19:42:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

readMethodsFor:aJavaClass
    |methodsCount method|

    "/
    "/ get methods
    "/
    methodsCount := inStream nextUnsignedShortMSB:msb.
    Verbose ifTrue:[Transcript show:'methodsCount = '; showCR:methodsCount].

    1 to:methodsCount do:[:i |
        Verbose ifTrue:[Transcript show:'method: '; showCR:i].
        method := self readMethodFor:aJavaClass
    ].

    "
     JavaClassReader readFile:'/phys/ibm3/hotjava/classes/browser/AddButton.class'
    "

    "Created: / 15.4.1996 / 16:46:30 / cg"
    "Modified: / 8.5.1998 / 21:20:59 / cg"
! !

!JavaClassReader methodsFor:'file reading - methods-ST'!

readSTCodeAttributeFor:aSmalltalkMethod
    |attribute_length max_stack max_locals code_length code
     exception_table_length unknown1 unknown2|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    Verbose ifTrue:[Transcript show:'attribute_length: 0x'; showCR:(attribute_length printStringRadix:16)].

    max_stack := inStream nextUnsignedShortMSB:msb.
    max_locals := inStream nextUnsignedShortMSB:msb.

    code_length := inStream nextUnsignedLongMSB:msb.
    Verbose ifTrue:[Transcript show:'code_length: '; showCR:(code_length printStringRadix:16)].
    Verbose ifTrue:[Transcript show:'code at pos: '; showCR:inStream position].

    code_length ~~ 0 ifTrue:[
        code := ByteArray new:code_length.
        inStream nextBytes:code_length into:code startingAt:1.
    ].
    Verbose ifTrue:[Transcript show:'method code: '; showCR:code.].

    exception_table_length := inStream nextUnsignedShortMSB:msb.
    Verbose ifTrue:[Transcript show:'exception_table_length: '; showCR:(exception_table_length printStringRadix:16)].
    exception_table_length ~~ 0 ifTrue:[
        self error:'unexpected exceptionTable length'.
        "/ skip it.
        1 to:exception_table_length do:[:i |
            "start_pc :="   inStream nextUnsignedShortMSB:msb.
            "end_pc :="     inStream nextUnsignedShortMSB:msb.
            "handler_pc :=" inStream nextUnsignedShortMSB:msb.
            "catch_type :=" inStream nextUnsignedShortMSB:msb.
        ].
    ].

    aSmalltalkMethod byteCode:code. 
    aSmalltalkMethod stackSize:max_stack .
    aSmalltalkMethod numberOfVars:max_locals. 

    self readAttributesFor:aSmalltalkMethod.
    ^ true

    "Modified: / 16.5.1998 / 01:39:30 / cg"
!

readSTLiteralsAttributeFor:aSmalltalkMethod
    |attribute_length literal_table_length literal_table litIndex literal|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    literal_table_length := inStream nextUnsignedShortMSB:msb.
    literal_table_length ~~ 0 ifTrue:[
        literal_table := Array new:literal_table_length.
        1 to:literal_table_length do:[:i |
            litIndex := inStream nextUnsignedShortMSB:msb.
            literal := (constants at:litIndex).
            literal_table at:i put:literal.
        ].
    ].
    Verbose ifTrue:[Transcript show:'literals: '; showCR:literal_table storeString.].

    "Created: / 7.5.1998 / 11:52:28 / cg"
    "Modified: / 16.5.1998 / 01:52:27 / cg"
!

readSTMethodCategoryAttributeFor:aSmalltalkMethod
    |attribute_length name_index name|

    attribute_length := inStream nextUnsignedLongMSB:msb.

    name_index := inStream nextUnsignedShortMSB:msb.
    name := (constants at:name_index).

    aSmalltalkMethod category:name.

    "Modified: / 8.5.1998 / 20:39:59 / cg"
    "Created: / 16.5.1998 / 01:04:19 / cg"
! !

!JavaClassReader methodsFor:'helpers'!

loadSuperclassIdentifiedBy: something ignoring: classesBeingLoaded 
    "overriding method, here we expect something to be new JavaClassRef2"

    self assert: something isJavaRef
        message: 'class identifier is not a java reference'.

    self assert: something isJavaClassRef
        message: 'class identifier is not a java class reference'.

    (classesBeingLoaded includes: something fullName) ifTrue: 
        [self error: 'class we want to load is being loaded and that means something went wrong. tell mh'].

    "Do NOT use >>something resolve<< here, since something
     has no owner set and therefore access check will cause DNU.
     Ask JV for details."

    ^Java classForName: something javaClassName.

    "Created: / 18-05-2011 / 14:55:32 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
    "Modified: / 22-05-2011 / 13:58:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

updateOwnerInCPItem: each 
    ((each isJavaRef and: [ each isNewJavaRef ]) 
        or: [ each isJavaNameAndType and: [ each isNewJavaNameAndType ] ]) 
            ifTrue: [ each owner: classBeingLoaded ].

    "Created: / 12-05-2011 / 17:40:46 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
!

updateOwnerInField: each 

            each setClass: classBeingLoaded.

    "Created: / 18-05-2011 / 13:57:20 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaClassReader methodsFor:'logging'!

info: message 
    Verbose ifTrue: [ Transcript showCR: message printString ].

    "Created: / 18-05-2011 / 15:06:06 / Marcel Hlopko <hlopkmar@fel.cvut.cz>"
! !

!JavaClassReader class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libjava/JavaClassReader.st,v 1.93 2011-08-18 18:42:48 vrany Exp $'
!

version_CVS
    ^ '§Header: /home/jv/Projects/SmalltalkX/repositories/cvs/stx/libjava/JavaClassReader.st,v 1.92 2009/10/09 14:21:53 cg Exp §'
!

version_SVN
    ^ '$Id: JavaClassReader.st,v 1.93 2011-08-18 18:42:48 vrany Exp $'
! !

JavaClassReader initialize!