1+ /*
2+ D-Bus Java Implementation
3+ Copyright (c) 2019 Technolution BV
4+
5+ This program is free software; you can redistribute it and/or modify it
6+ under the terms of either the GNU Lesser General Public License Version 2 or the
7+ Academic Free Licence Version 2.1.
8+
9+ Full licence texts are included in the LICENSE file with this program.
10+ */
11+
12+ package org .freedesktop .dbus .messages ;
13+
14+ import java .util .Arrays ;
15+
16+ final class EmptyCollectionHelper {
17+
18+ /**
19+ * This function determine the new offset in signature for empty Dictionary/Map collections.
20+ * Normally the element inside a collection determines the new offset,
21+ * however in case of empty collections there is no element to determine the sub signature of the list
22+ * so this function determines which part of the signature to skip
23+ * @param sigb the total signature
24+ * @param currentOffset the current offset within the signature
25+ * @return the index of the last element of the collection (subtype)
26+ */
27+ static int determineSignatureOffsetDict (byte [] sigb , int currentOffset ) {
28+ return determineEndOfBracketStructure (sigb , currentOffset , '{' , '}' );
29+ }
30+
31+ /**
32+ * This function determine the new offset in signature for empty Array/List collections.
33+ * Normally the element inside a collection determines the new offset,
34+ * however in case of empty collections there is no element to determine the sub signature of the list
35+ * so this function determines which part of the signature to skip
36+ * @param sigb the total signature
37+ * @param currentOffset the current offset within the signature
38+ * @return the index of the last element of the collection (subtype)
39+ */
40+ static int determineSignatureOffsetArray (byte [] sigb , int currentOffset ) {
41+ String sigSubString = determineSubSignature (sigb , currentOffset );
42+
43+ // End of string so can't have any more offset
44+ if (sigSubString .isEmpty ()) {
45+ return currentOffset ;
46+ }
47+
48+ ECollectionSubType newtype = determineCollectionSubType ((char )sigb [currentOffset ]);
49+ switch (newtype ) {
50+ case ARRAY :
51+ // array in array so look at the next type
52+ return determineSignatureOffsetArray (sigb , currentOffset + 1 );
53+ case DICT :
54+ return determineSignatureOffsetDict (sigb , currentOffset );
55+ case STRUCT :
56+ return determineSignatureOffsetStruct (sigb , currentOffset );
57+ case PRIMITIVE :
58+ //primitive is always one element so no need to skip more
59+ return currentOffset ;
60+ default :
61+ break ;
62+
63+ }
64+ throw new IllegalStateException ("Unable to parse signature for empty collection" );
65+ }
66+
67+ private static int determineSignatureOffsetStruct (byte [] sigb , int currentOffset ) {
68+ return determineEndOfBracketStructure (sigb , currentOffset , '(' , ')' );
69+ }
70+
71+ /**
72+ * This is a generic function to determine the end of a structure that has opening and closing characters.
73+ * Currently used for Struct () and Dict {}
74+ *
75+ */
76+ private static int determineEndOfBracketStructure (byte [] sigb , int currentOffset , char openChar , char closeChar ) {
77+ String sigSubString = determineSubSignature (sigb , currentOffset );
78+
79+ // End of string so can't have any more offset
80+ if (sigSubString .isEmpty ()) {
81+ return currentOffset ;
82+ }
83+ int i = 0 ;
84+ int depth = 0 ;
85+
86+ for (char chr : sigSubString .toCharArray ()) {
87+ //book keeping of depth of nested structures to solve opening closing bracket problem
88+ if (chr == openChar ) {
89+ depth ++;
90+ } else if (chr == closeChar ) {
91+ depth --;
92+ }
93+ if (depth == 0 ) {
94+ return currentOffset + i ;
95+ }
96+ i ++;
97+ }
98+ throw new IllegalStateException ("Unable to parse signature for empty collection" );
99+ }
100+
101+ private static String determineSubSignature (byte [] sigb , int currentOffset ) {
102+ byte [] restSigbytes = Arrays .copyOfRange (sigb , currentOffset , sigb .length );
103+ return new String (restSigbytes );
104+ }
105+
106+ /**
107+ * The starting type determines of a collection determines when it ends
108+ * @param sig the signature letter of the type
109+ */
110+ private static ECollectionSubType determineCollectionSubType (char sig ) {
111+ switch (sig ) {
112+ case '(' :
113+ return ECollectionSubType .STRUCT ;
114+ case '{' :
115+ return ECollectionSubType .DICT ;
116+ case 'a' :
117+ return ECollectionSubType .ARRAY ;
118+ default :
119+ // of course there can be other types but those shouldn't be allowed in this part of the signature
120+ return ECollectionSubType .PRIMITIVE ;
121+ }
122+ }
123+
124+ /**
125+ * Internal Enumeration used to group the types of element
126+ */
127+ enum ECollectionSubType {
128+ STRUCT ,
129+ DICT ,
130+ ARRAY ,
131+ PRIMITIVE
132+ }
133+ }
0 commit comments