Re: JavaXPCOM: How to handle unsigned 8-bit values?

Michal Ceresna <[email protected]>
Newsgroups gmane.comp.mozilla.devel.java
Message-ID <200704241044.10497.michal.ceresna__17420.1202615679$1177404499$gmane$org@gmail.com>
On Monday 23 April 2007, Javier Pedemonte wrote:

Hello Javier,

> 3) Promote everything but 'octet' values.  This way, the user doesn't
> need to worry about unsigned values, except for byte.  And since byte
> arrays are often used for passing around data, there is no need to first
> copy the data to a short array.

Sounds good. 

All usages of 'octet' seem to occur only in array declarations.

I would even suggest also to not promote PRUint8[] arrays.
(see the usage patterns below)

best regards,
Michal


Various declaration patterns of primitive-type arrays in IDL interfaces:

unsigned long:
  mozIStorageStatement.idl:     [array,size_is(aCount),retval] out unsigned long aIndexes);

long:
  nsIAccessibleTable.idl:          [retval, array, size_is(columnsSize)] out longcolumns);
  nsIAccessibleTable.idl:          [retval, array, size_is(rowsSize)] out long rows);

PRInt64:
  nsINavHistoryService.idl:                  [retval,array,size_is(count)] out PRInt64 folders);
  nsINavHistoryService.idl:  void setFolders([const,array, size_is(folderCount)] in PRInt64 folders,

PRInt32:
  nsINavHistoryService.idl:                       [retval,array,size_is(groupCount)] out PRUint32 groupingMode);
  nsINavHistoryService.idl:  void setGroupingMode([const,array,size_is(groupCount)] in PRUint32 groupingMode,

PRUnichar:
  nsIUnicharInputStream.idl:  [noscript] unsigned long read([array, size_is(aCount)] in PRUnichar aBuf,
  nsIUnicharOutputStream.idl:                  [const, array, size_is(aCount)] inPRUnichar c);

PRUint8:
  gfxIImageFrame.idl:  void getImageData([array, size_is(length)] out PRUint8 bits, out unsigned long length);
  gfxIImageFrame.idl:  void setImageData([array, size_is(length), const] in PRUint8 data,
  gfxIImageFrame.idl:  void getAlphaData([array, size_is(length)] out PRUint8 bits, out unsigned long length);
  gfxIImageFrame.idl:  void setAlphaData([array, size_is(length), const] in PRUint8 data,
  imgIEncoder.idl:  void initFromData([array, size_is(length), const] in PRUint8 data,
  nsIBinaryInputStream.idl:                       [array, size_is(aLength), retval] out PRUint8 aBytes);
  nsIBinaryOutputStream.idl:    void writeByteArray([array, size_is(aLength)] in PRUint8 aBytes,

octet:
  mozIStorageValueArray.idl:  void getBlob(in unsigned long aIndex, out unsigned long aDataSize, [array,size_is(aDataSize)] out octet aData);
  nsIAnnotationService.idl:                             [const,array,size_is(aDataLen)] in octet aData,
  nsIAnnotationService.idl:                             [array,size_is(aDataLen)] out octet aData,nsICRLManager.idl:  void importCrl([array, size_is(length)] in octet data,
  nsICollation.idl:                                     [array,size_is(outLen)] out octet key,
  nsICollation.idl:  [noscript] long compareRawSortKey([const,array,size_is(len1)] in octet key1, in unsigned long len1,
  nsICollation.idl:                                    [const,array,size_is(len2)] in octet key2, in unsigned long len2);
  nsIContentSniffer.idl:                                  [const,array,size_is(aLength)] in octet aData,
  nsICryptoHash.idl:    void update([const, array, size_is(aLen)] in octet aData,in unsigned long aLen);
  nsIDOMParser.idl:  nsIDOMDocument parseFromBuffer([const,array,size_is(bufLen)]in octet buf,
  nsIFaviconService.idl:                      [const,array,size_is(aDataLen)] in octet aData,
  nsIKeyModule.idl:                         [const, array, size_is(aWrappedKeyLen)] in octet aWrappedKey,
  nsIScriptableUConv.idl:  AString convertFromByteArray([const,array,size_is(aCount)] in octet aData,
  nsIScriptableUConv.idl:                          [array, size_is(aLen),retval] out octet aData);
  nsIStreamCipher.idl:                    [const, array, size_is(aIVLen)] in octet aIV,
  nsIStreamCipher.idl:    void update([const, array, size_is(aLen)] in octet aData, in unsigned long aLen);
  nsIStreamLoader.idl:                          [const,array,size_is(resultLength)] in octet result);
  nsIWebBrowserStream.idl:  void appendToStream([const, array, size_is(aLen)] in octet aData,
  nsIX509Cert.idl:                       [retval, array, size_is(length)] out octet data);
  nsIX509CertDB.idl:  void importCertificates([array, size_is(length)] in octet data,
  nsIX509CertDB.idl:  void importEmailCertificate([array, size_is(length)] in octet data,
  nsIX509CertDB.idl:  void importServerCertificate([array, size_is(length)] in octet data,
  nsIX509CertDB.idl:  void importUserCertificate([array, size_is(length)] in octet data,

Used command:
grep 'array,[ ]*size.*\(in\|out\)' *.idl | grep -v '[ \t]*\(#\|\*\|//\)' | grep -v 'array, *size_is(\w*)\(,[ ]*retval\)*\(,[ ]*const\)*] \(in\|out\) \(nsI\|jsdI\|wstring\|string\|octet\|PRUint8\|PRUnichar\|PRUint32\|PRInt64\long\|unsigned long\)' | less

> Java doesn't support unsigned values.  However, many of the Mozilla
> interfaces take or return unsigned values.  The solution in JavaXPCOM
> has been to 'promote' the unsigned types to the next larger type in
> Java, such that the larger type can handle the full range of the
> unsigned type.  So, for example, a Mozilla interface that returns an
> 'unsigned int' in Java is defined to return a 'long'.
>
> But this doesn't work that well for 8-bit (byte) values, since byte
> arrays are often used to pass around large chunks of data.  Take for
> example the nsIWebBrowserStream.appendToStream() function
> (http://mxr.mozilla.org/mozilla/source/embedding/browser/webBrowser/nsIWebB
>rowserStream.idl#73). According to the XPIDL file, it takes an 'octet' array
> of data
> ('octet' is defined in XPIDL as an unsigned 8-bit value).
>
> In Java, it would be natural to want to do something like this:
> 	String htmlData = ...;
> 	byte[] bytes = htmlData.getBytes("UTF-8");
> 	webBrowserStream.appendToStream(bytes, bytes.length);
>
> However, since 'octet' is promoted to the Java 'short', we must first
> convert the byte array returned by getBytes() to a short array, before
> passing it to appendToStream().  Of course, under the covers, JavaXPCOM
> will then convert the short array to a C++ byte array, meaning that in
> the end, this array is converted twice to essentially get what we
> started with.
>
>
> I see three ways that JavaXPCOM could handle unsigned values:
>
> 1) Promote every XPIDL type to the next larger Java type.  This makes it
> easiest on the JavaXPCOM user, since they can see the full range of
> values and not have to worry about tricks for getting the 'unsigned'
> value.  However, for 'octet' arrays, it may require to the user to go
> through an extra step, as illustrated above.
>
> 2) Don't promote anything; C++ type == Java type.  This avoids the issue
> above.  However, the user must now take care when working with unsigned
> parameters.  In most cases, since they want the actual value, the user
> will do the unsigned conversion themselves by putting the value in the
> next larger type.
>
> 3) Promote everything but 'octet' values.  This way, the user doesn't
> need to worry about unsigned values, except for byte.  And since byte
> arrays are often used for passing around data, there is no need to first
> copy the data to a short array.
>
>
> I prefer the 3rd option.  What does everyone else here think?
>
>
> javier pedemonte
> _______________________________________________
> dev-tech-java mailing list
> [email protected]
> https://lists.mozilla.org/listinfo/dev-tech-java
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.