1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef AAPT_JAVA_CLASSDEFINITION_H
18 #define AAPT_JAVA_CLASSDEFINITION_H
19 
20 #include <ostream>
21 #include <string>
22 
23 #include "android-base/macros.h"
24 #include "androidfw/StringPiece.h"
25 
26 #include "Resource.h"
27 #include "java/AnnotationProcessor.h"
28 #include "util/Util.h"
29 
30 namespace aapt {
31 
32 // The number of attributes to emit per line in a Styleable array.
33 constexpr static size_t kAttribsPerLine = 4;
34 constexpr static const char* kIndent = "  ";
35 
36 class ClassMember {
37  public:
38   virtual ~ClassMember() = default;
39 
GetCommentBuilder()40   AnnotationProcessor* GetCommentBuilder() { return &processor_; }
41 
42   virtual bool empty() const = 0;
43 
44   // Writes the class member to the out stream. Subclasses should derive this method
45   // to write their own data. Call this base method from the subclass to write out
46   // this member's comments/annotations.
47   virtual void WriteToStream(const android::StringPiece& prefix, bool final,
48                              std::ostream* out) const;
49 
50  private:
51   AnnotationProcessor processor_;
52 };
53 
54 template <typename T>
55 class PrimitiveMember : public ClassMember {
56  public:
PrimitiveMember(const android::StringPiece & name,const T & val)57   PrimitiveMember(const android::StringPiece& name, const T& val)
58       : name_(name.to_string()), val_(val) {}
59 
empty()60   bool empty() const override { return false; }
61 
WriteToStream(const android::StringPiece & prefix,bool final,std::ostream * out)62   void WriteToStream(const android::StringPiece& prefix, bool final,
63                      std::ostream* out) const override {
64     ClassMember::WriteToStream(prefix, final, out);
65 
66     *out << prefix << "public static " << (final ? "final " : "") << "int "
67          << name_ << "=" << val_ << ";";
68   }
69 
70  private:
71   std::string name_;
72   T val_;
73 
74   DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
75 };
76 
77 /**
78  * Specialization for strings so they get the right type and are quoted with "".
79  */
80 template <>
81 class PrimitiveMember<std::string> : public ClassMember {
82  public:
PrimitiveMember(const android::StringPiece & name,const std::string & val)83   PrimitiveMember(const android::StringPiece& name, const std::string& val)
84       : name_(name.to_string()), val_(val) {}
85 
empty()86   bool empty() const override { return false; }
87 
WriteToStream(const android::StringPiece & prefix,bool final,std::ostream * out)88   void WriteToStream(const android::StringPiece& prefix, bool final,
89                      std::ostream* out) const override {
90     ClassMember::WriteToStream(prefix, final, out);
91 
92     *out << prefix << "public static " << (final ? "final " : "") << "String "
93          << name_ << "=\"" << val_ << "\";";
94   }
95 
96  private:
97   std::string name_;
98   std::string val_;
99 
100   DISALLOW_COPY_AND_ASSIGN(PrimitiveMember);
101 };
102 
103 using IntMember = PrimitiveMember<uint32_t>;
104 using ResourceMember = PrimitiveMember<ResourceId>;
105 using StringMember = PrimitiveMember<std::string>;
106 
107 template <typename T>
108 class PrimitiveArrayMember : public ClassMember {
109  public:
PrimitiveArrayMember(const android::StringPiece & name)110   explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
111 
AddElement(const T & val)112   void AddElement(const T& val) { elements_.push_back(val); }
113 
empty()114   bool empty() const override { return false; }
115 
WriteToStream(const android::StringPiece & prefix,bool final,std::ostream * out)116   void WriteToStream(const android::StringPiece& prefix, bool final,
117                      std::ostream* out) const override {
118     ClassMember::WriteToStream(prefix, final, out);
119 
120     *out << prefix << "public static final int[] " << name_ << "={";
121 
122     const auto begin = elements_.begin();
123     const auto end = elements_.end();
124     for (auto current = begin; current != end; ++current) {
125       if (std::distance(begin, current) % kAttribsPerLine == 0) {
126         *out << "\n" << prefix << kIndent << kIndent;
127       }
128 
129       *out << *current;
130       if (std::distance(current, end) > 1) {
131         *out << ", ";
132       }
133     }
134     *out << "\n" << prefix << kIndent << "};";
135   }
136 
137  private:
138   std::string name_;
139   std::vector<T> elements_;
140 
141   DISALLOW_COPY_AND_ASSIGN(PrimitiveArrayMember);
142 };
143 
144 using ResourceArrayMember = PrimitiveArrayMember<ResourceId>;
145 
146 // Represents a method in a class.
147 class MethodDefinition : public ClassMember {
148  public:
149   // Expected method signature example: 'public static void onResourcesLoaded(int p)'.
MethodDefinition(const android::StringPiece & signature)150   explicit MethodDefinition(const android::StringPiece& signature)
151       : signature_(signature.to_string()) {}
152 
153   // Appends a single statement to the method. It should include no newlines or else
154   // formatting may be broken.
155   void AppendStatement(const android::StringPiece& statement);
156 
157   // Even if the method is empty, we always want to write the method signature.
empty()158   bool empty() const override { return false; }
159 
160   void WriteToStream(const android::StringPiece& prefix, bool final,
161                      std::ostream* out) const override;
162 
163  private:
164   std::string signature_;
165   std::vector<std::string> statements_;
166 };
167 
168 enum class ClassQualifier { kNone, kStatic };
169 
170 class ClassDefinition : public ClassMember {
171  public:
172   static bool WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
173                             bool final, std::ostream* out);
174 
ClassDefinition(const android::StringPiece & name,ClassQualifier qualifier,bool createIfEmpty)175   ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
176       : name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
177 
AddMember(std::unique_ptr<ClassMember> member)178   void AddMember(std::unique_ptr<ClassMember> member) {
179     members_.push_back(std::move(member));
180   }
181 
182   bool empty() const override;
183   void WriteToStream(const android::StringPiece& prefix, bool final,
184                      std::ostream* out) const override;
185 
186  private:
187   std::string name_;
188   ClassQualifier qualifier_;
189   bool create_if_empty_;
190   std::vector<std::unique_ptr<ClassMember>> members_;
191 
192   DISALLOW_COPY_AND_ASSIGN(ClassDefinition);
193 };
194 
195 }  // namespace aapt
196 
197 #endif /* AAPT_JAVA_CLASSDEFINITION_H */
198