home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / fnb101.zip / Lib / site-packages / Fnorb / orb / OctetStream.py < prev    next >
Text File  |  1999-06-28  |  13KB  |  431 lines

  1. #!/usr/bin/env python
  2. #############################################################################
  3. # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999
  4. # All Rights Reserved.
  5. #
  6. # The software contained on this media is the property of the DSTC Pty
  7. # Ltd.  Use of this software is strictly in accordance with the
  8. # license agreement in the accompanying LICENSE.HTML file.  If your
  9. # distribution of this software does not contain a LICENSE.HTML file
  10. # then you have no rights to use this software in any manner and
  11. # should contact DSTC at the address below to determine an appropriate
  12. # licensing arrangement.
  13. #      DSTC Pty Ltd
  14. #      Level 7, GP South
  15. #      Staff House Road
  16. #      University of Queensland
  17. #      St Lucia, 4072
  18. #      Australia
  19. #      Tel: +61 7 3365 4310
  20. #      Fax: +61 7 3365 4311
  21. #      Email: enquiries@dstc.edu.au
  22. # This software is being provided "AS IS" without warranty of any
  23. # kind.  In no event shall DSTC Pty Ltd be liable for damage of any
  24. # kind arising out of or in connection with the use or performance of
  25. # this software.
  26. #
  27. # Project:      Fnorb
  28. # File:         $Source: /units/arch/src/Fnorb/orb/RCS/OctetStream.py,v $
  29. # Version:      @(#)$RCSfile: OctetStream.py,v $ $Revision: 1.16 $
  30. #
  31. #############################################################################
  32. """ Classes for CORBA octet streams, encapsulations and GIOP messages. """
  33.  
  34.  
  35. # Standard/built-in modules.
  36. import new
  37.  
  38. # Fnorb modules.
  39. import CORBA, GIOP, Util
  40.  
  41. # Fnorb extension modules.
  42. import cdr
  43.  
  44. # Fnorb parser modules.
  45. from Fnorb.parser import Stack
  46.  
  47.  
  48. class OctetStream:
  49.     """ CORBA octet streams. """
  50.  
  51.     # The initial size of a new stream.
  52.     INITIAL_SIZE = 512
  53.  
  54.     def __init__(self, data=None):
  55.     """ Constructor.
  56.  
  57.     'data' is the contents of the octet stream.
  58.  
  59.     """
  60.     # If no data is specified then we initially allocate a fixed size
  61.     # string and then grow it (ie. get a bigger, better, brighter, wider,
  62.     # faster string) as required.
  63.     if data is None:
  64.         self._data = '\0' * OctetStream.INITIAL_SIZE
  65.         self._len = 0
  66.  
  67.     # If data *is* specified then we use that!
  68.     else:
  69.         self._data = data
  70.         self._len = len(data)
  71.  
  72.     return
  73.  
  74.     def __del__(self):
  75.     
  76.     del self._data
  77.     return
  78.  
  79.     def __len__(self):
  80.     """ Return the number of octets in the stream.
  81.  
  82.     This is the number of octets actually marshalled in the stream - not
  83.     the internal buffer size!
  84.  
  85.     """
  86.     return self._len
  87.  
  88.     def marshal(self, format, value, offset, byte_order):
  89.     """ Marshal a value onto the octet stream.
  90.  
  91.     'format'     identifies the type of the data to be marshalled.
  92.     'value'      is the data to be marshalled!
  93.     'offset'     is the offset in the stream to marshal the data into.
  94.     'byte_order' is the byte ordering to use when marshalling the data.
  95.  
  96.     The return value is the offset in the stream after marshalling the
  97.     data.
  98.  
  99.     """
  100.     # Calculate the space required to marshal the data onto the octet
  101.     # stream.  If the value won't fit into the string that is currently
  102.     # allocated then we create a new, larger one.
  103.     new_offset = cdr.count(format,
  104.                    self._data, # Not modified by this call.
  105.                    offset,
  106.                    byte_order,
  107.                    value)
  108.  
  109.     # If a new string is required, then make it plenty big enough!
  110.     if new_offset > len(self._data):
  111.         # For now we'll make the new string twice as big as required.
  112.         new_len = new_offset * 2
  113.         self._data = self._data + ('\0' * (new_len - len(self._data)))
  114.  
  115.     # Now marshal the data onto the octet stream.
  116.     new_offset = cdr.marshal(format,
  117.                  self._data,
  118.                  offset,
  119.                  byte_order,
  120.                  value)
  121.  
  122.     # Have we increased the *actual* length of the data in the octet
  123.     # stream?
  124.     if new_offset > self._len:
  125.         self._len = new_offset
  126.  
  127.     return new_offset
  128.  
  129.     def unmarshal(self, format, offset, byte_order):
  130.     """ Unmarshal a value from the octet stream.
  131.  
  132.     'format'     identifies the type of the data to be unmarshalled.
  133.     'offset'     is the offset in the stream to unmarshal the data from.
  134.     'byte_order' is the byte ordering to use when unmarshalling the data.
  135.     
  136.     The return value is a tuple (NewOffset, Value) where 'NewOffset' is the
  137.     offset after unmarshalling the value, and 'Value' (surprise, surprise)
  138.     is the value that was unmarshalled.
  139.  
  140.     """
  141.     return cdr.unmarshal(format, self._data, offset, byte_order)
  142.  
  143.     def data(self):
  144.     """ Return the contents of the octet stream. """
  145.  
  146.     return self._data[:self._len]
  147.  
  148.     def cursor(self, offset=0, byte_order=Util.HOST_BYTE_ORDER):
  149.     """ Return a cursor suitable for iterating over me! """
  150.  
  151.     return OctetStreamCursor(self, offset, byte_order)
  152.  
  153.  
  154. class OctetStreamCursor:
  155.     """ A class to allow iteration over an OctetStream. """
  156.  
  157. ##    def __init__(self, stream, offset, byte_order=Util.HOST_BYTE_ORDER):
  158.     def __init__(self, stream, offset, byte_order, stack=None):
  159.     """ Constructor.
  160.  
  161.     'stream'     is the octet stream to iterate over.
  162.     'offset'     is the starting position within the octet stream.
  163.     'byte_order' is the byte ordering to use when marshalling/unmarshalling
  164.                  data.
  165.  
  166.     """
  167.     self._stream = stream
  168.     self._offset = offset
  169.     self._byte_order = byte_order
  170.  
  171.     # Container stack for marshalling/unmarshalling recursive types.
  172.     #
  173.     # In the case of an encapsulation cursor, the stack is inherited from
  174.     # the cursor that created it.
  175.     if stack is not None:
  176.         self._stack = stack
  177.  
  178.     else:
  179.         self._stack = Stack.Stack()
  180.  
  181.     return
  182.  
  183.     def stream(self):
  184.     """ Return the octet stream that we are iterating over. """
  185.  
  186.     return self._stream
  187.  
  188.     def offset(self):
  189.     """ Return the current offset in the octet stream. """
  190.  
  191.     return self._offset
  192.  
  193.     def set_offset(self, offset):
  194.     """ Set the offeset in the octet stream. """
  195.  
  196.     self._offset = offset
  197.     return
  198.  
  199.     def byte_order(self):
  200.     """ Return the byte ordering of the cursor. """
  201.  
  202.     return self._byte_order
  203.  
  204.     def marshal(self, format, value):
  205.     """ Marshal a value onto the octet stream.
  206.  
  207.     'format' identifies the type of the data to be marshalled.
  208.     'value'  is the data to be marshalled!
  209.  
  210.     """
  211.     self._offset = self._stream.marshal(format,
  212.                         value,
  213.                         self._offset,
  214.                         self._byte_order)
  215.     return
  216.  
  217.     def unmarshal(self, format):
  218.     """ Unmarshal a value from the octet stream.
  219.  
  220.     'format' identifies the type of the data to be unmarshalled.
  221.  
  222.     The return value is the value that was unmarshalled.
  223.  
  224.     """
  225.     (self._offset, value) = self._stream.unmarshal(format,
  226.                                self._offset,
  227.                                self._byte_order)
  228.     return value
  229.  
  230.     # fixme: How does this work with regard to calculating padding?
  231.     #
  232.     # answer: I think it works 'cos no item within an encapsulation requires
  233.     # a byte boundary of anything more than a multiple of four, therefore, by
  234.     # the time we have aligned the length of the encapsulation then we have
  235.     # forced the necessary alignment.
  236.     def encapsulation_cursor(self):
  237.     """ Return a new cursor at the start of an encapsulation. """
  238.  
  239.     # Skip over the length of the encapsulation.
  240.     (offset, length) = self._stream.unmarshal('L',
  241.                           self._offset,
  242.                           self._byte_order)
  243.  
  244.     # Get the byte order of the encapsulation.
  245.     (offset, byte_order) = self._stream.unmarshal('b',
  246.                               offset,
  247.                               self._byte_order)
  248.  
  249.     # Create a new cursor with the specified byte order (the cursor also
  250.     # inherits the stack for marshalling/unmarshalling recursive types).
  251.     return OctetStreamCursor(self._stream, offset, byte_order, self._stack)
  252.  
  253.     def stack(self):
  254.     """ Return the stack of containers.
  255.  
  256.     This is used to marshal and unmarshal recursive types.
  257.  
  258.     """
  259.     return self._stack
  260.  
  261.  
  262. class Encapsulation(OctetStream):
  263.     """ CORBA encapsulations. """
  264.  
  265.     def __init__(self, data=None, byte_order=Util.HOST_BYTE_ORDER):
  266.     """ Constructor.
  267.  
  268.     'data'       is the contents of the octet stream.
  269.     'byte_order' is the byte order of the octet stream!
  270.  
  271.     """
  272.     # The byte order of the octet stream.
  273.     self._byte_order = byte_order
  274.  
  275.     # If no data is specified then we initially allocate a fixed size
  276.     # string and then grow it (ie. get a bigger, better, brighter, wider,
  277.     # faster string) as required.
  278.     if data is None:
  279.         self._data = "\0" * OctetStream.INITIAL_SIZE
  280.         self._len = 0
  281.  
  282.         # Marshal the byte order onto the first octet in the stream.
  283.         offset = self.marshal('b', self._byte_order, 0, self._byte_order)
  284.  
  285.     # If data *is* specified then we use that!
  286.     else:
  287.         self._data = data
  288.         self._len = len(data)
  289.  
  290.         # Get the byte order of the encapsulation (held in the first
  291.         # octet).
  292.         (offset, self._byte_order) = self.unmarshal('b',0,self._byte_order)
  293.  
  294.     return
  295.  
  296.     def cursor(self, offset=1):
  297.     """ Return a cursor suitable for iterating over me! """
  298.  
  299.     return OctetStreamCursor(self, offset, self._byte_order)
  300.  
  301.  
  302. class GIOPMessage(OctetStream):
  303.     """ GIOP messages. """
  304.  
  305.     # Current version of GIOP.
  306.     __GIOP_VERSION = GIOP.Version(Util.GIOP_VERSION_MAJOR,
  307.                   Util.GIOP_VERSION_MINOR)
  308.  
  309.     def __init__(self, data=None, byte_order=Util.HOST_BYTE_ORDER, type=None):
  310.     """ Constructor.
  311.  
  312.     'data'       is the contents of the octet stream.
  313.     'byte_order' is the byte order of the octet stream!
  314.     'type'       is the type of GIOP message ;^)
  315.  
  316.     """
  317.     # The byte order of the octet stream.
  318.     self._byte_order = byte_order
  319.  
  320.     # If no data is specified then we initially allocate a fixed size
  321.     # string and then grow it (ie. get a bigger, better, brighter, wider,
  322.     # faster string) as required.
  323.     if data is None:
  324.         self._data = "\0" * OctetStream.INITIAL_SIZE
  325.         self._len = 0
  326.  
  327.         # Marshal a GIOP header onto the stream.
  328.         self._header = self._marshal_header(type)
  329.  
  330.     # If data *is* specified then we use that!
  331.     else:
  332.         self._data = data
  333.         self._len = len(data)
  334.  
  335.         # Get the byte order of the message (held in the sixth octet!).
  336.         (offset, self._byte_order) = self.unmarshal('b',6,self._byte_order)
  337.  
  338.         # Unmarshal the GIOP header from the stream.
  339.         self._header = self._unmarshal_header()
  340.  
  341.     return
  342.  
  343.     def header(self):
  344.     """ Return the GIOP message header. """
  345.     
  346.     return self._header
  347.  
  348.     def data(self):
  349.     """ Return the contents of the octet stream. """
  350.  
  351.     # Fixup the length in the GIOP header.
  352.     cdr.marshal('L', self._data, 8, self._byte_order, self._len - 12)
  353.  
  354.     return OctetStream.data(self)
  355.  
  356.     def cursor(self, offset=12):
  357.     """ Return a cursor suitable for iterating over me! """
  358.  
  359.     return OctetStreamCursor(self, offset, self._byte_order)
  360.  
  361.     #########################################################################
  362.     # Internal methods.
  363.     #########################################################################
  364.  
  365.     def _marshal_header(self, message_type):
  366.     """ Marshal a GIOP header onto the start of the stream.
  367.  
  368.     'message_type' is the type of GIOP message ;^)
  369.  
  370.     """
  371.     # Create a GIOP header (the size of the message is fixed up when
  372.     # the 'data' method is called!).
  373.     header = GIOP.MessageHeader(Util.MAGIC,
  374.                     GIOPMessage.__GIOP_VERSION,
  375.                     self._byte_order,
  376.                     message_type.value(),
  377.                     0) # Size
  378.  
  379.     tc = CORBA.typecode('IDL:omg.org/GIOP/MessageHeader:1.0')
  380.     tc._fnorb_marshal_value(self.cursor(0), header)
  381.  
  382.     return header
  383.  
  384.     def _unmarshal_header(self):
  385.     """ Unmarshal a GIOP header from the start of the stream. """
  386.  
  387.     # Unmarshal the header from the start of the stream.
  388.     tc = CORBA.typecode('IDL:omg.org/GIOP/MessageHeader:1.0')
  389.     return tc._fnorb_unmarshal_value(self.cursor(0))
  390.  
  391. #############################################################################
  392.  
  393. # Testing.
  394. if __name__ == '__main__':
  395.  
  396.     for stream in [OctetStream(), Encapsulation()]:
  397.     # Marshal some 'stuff' onto the stream...
  398.     cursor = stream.cursor(12)
  399.     cursor.marshal('b', 123)
  400.     cursor.marshal('c', 'X')
  401.     cursor.marshal('o', 125)
  402.     cursor.marshal('h', 126)
  403.     cursor.marshal('H', 127)
  404.     cursor.marshal('l', 128)
  405.     cursor.marshal('L', 129)
  406.     cursor.marshal('n', -9223372036854775808L)
  407.     cursor.marshal('N', 9223372036854775808L)
  408.     cursor.marshal('f', 130.456)
  409.     cursor.marshal('d', 131.456)
  410.     cursor.marshal('s', 'Hello World!')
  411.     cursor.marshal('O', 'Hello World!')
  412.     # ... and make sure it unmarshals correctly ;^)
  413.     cursor = stream.cursor(12)
  414.     print cursor.unmarshal('b')
  415.     print cursor.unmarshal('c')
  416.     print cursor.unmarshal('o')
  417.     print cursor.unmarshal('h')
  418.     print cursor.unmarshal('H')
  419.     print cursor.unmarshal('l')
  420.     print cursor.unmarshal('L')
  421.     print cursor.unmarshal('n')
  422.     print cursor.unmarshal('N')
  423.     print cursor.unmarshal('f')
  424.     print cursor.unmarshal('d')
  425.     print cursor.unmarshal('s')
  426.     print cursor.unmarshal('O')
  427.  
  428. #############################################################################
  429.