1#!/bin/bash
2#
3# Copyright (C) 2010 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18#
19# This script imports new versions of Bouncy Castle
20# (http://bouncycastle.org) into the Android source tree.  To run, (1)
21# fetch the appropriate tarballs (bcprov and bcpkix) from the Bouncy
22# Castle repository, (2) check the checksum, and then (3) run:
23#   ./import_bouncycastle.sh import bcprov-jdk*-*.tar.gz
24#
25# IMPORTANT: See README.android for additional details.
26
27# turn on exit on error as well as a warning when it happens
28set -e
29trap  "echo WARNING: Exiting on non-zero subprocess exit code" ERR;
30
31cd $(dirname $0)
32
33function die() {
34  declare -r message=$1
35
36  echo $message
37  exit 1
38}
39
40function usage() {
41  declare -r message=$1
42
43  if [ ! "$message" = "" ]; then
44    echo $message
45  fi
46  echo "Usage:"
47  echo "  ./import_bouncycastle.sh import </path/to/bcprov-jdk*-*.tar.gz>"
48  echo "  ./import_bouncycastle.sh regenerate <patch/*.patch>"
49  echo "  ./import_bouncycastle.sh generate <patch/*.patch> </path/to/bcprov-jdk*-*.tar.gz>"
50  exit 1
51}
52
53function main() {
54  if [ ! -d patches ]; then
55    die "Bouncy Castle patch directory patches/ not found"
56  fi
57
58  if [ ! -f bouncycastle.version ]; then
59    die "bouncycastle.version not found"
60  fi
61
62  source ./bouncycastle.version
63  if [ "$BOUNCYCASTLE_JDK" == "" -o "$BOUNCYCASTLE_VERSION" == "" ]; then
64    die "Invalid bouncycastle.version; see README.android for more information"
65  fi
66
67  BOUNCYCASTLE_BCPROV_DIR=bcprov-jdk$BOUNCYCASTLE_JDK-$BOUNCYCASTLE_VERSION
68  BOUNCYCASTLE_BCPROV_DIR_ORIG=$BOUNCYCASTLE_BCPROV_DIR.orig
69
70  BOUNCYCASTLE_BCPKIX_DIR=bcpkix-jdk$BOUNCYCASTLE_JDK-$BOUNCYCASTLE_VERSION
71  BOUNCYCASTLE_BCPKIX_DIR_ORIG=$BOUNCYCASTLE_BCPKIX_DIR.orig
72
73  if [ ! -f bouncycastle.config ]; then
74    die "bouncycastle.config not found"
75  fi
76
77  source ./bouncycastle.config
78  if [ "$UNNEEDED_BCPROV_SOURCES" == "" -o "$NEEDED_BCPROV_SOURCES" == "" \
79    -o "$UNNEEDED_BCPKIX_SOURCES" == "" -o "$NEEDED_BCPKIX_SOURCES" == "" ]; then
80    die "Invalid bouncycastle.config; see README.android for more information"
81  fi
82
83  declare -r command=$1
84  shift || usage "No command specified. Try import, regenerate, or generate."
85  if [ "$command" = "import" ]; then
86    declare -r bcprov_tar=$1
87    shift || usage "No tar file specified."
88    declare -r bcpkix_tar=`echo $bcprov_tar | sed s/bcprov/bcpkix/`
89    import $bcprov_tar $BOUNCYCASTLE_BCPROV_DIR $BOUNCYCASTLE_BCPROV_DIR_ORIG bcprov "$BOUNCYCASTLE_BCPROV_PATCHES" "$NEEDED_BCPROV_SOURCES" "$UNNEEDED_BCPROV_SOURCES"
90    import $bcpkix_tar $BOUNCYCASTLE_BCPKIX_DIR $BOUNCYCASTLE_BCPKIX_DIR_ORIG bcpkix "$BOUNCYCASTLE_BCPKIX_PATCHES" "$NEEDED_BCPKIX_SOURCES" "$UNNEEDED_BCPKIX_SOURCES"
91  elif [ "$command" = "regenerate" ]; then
92    declare -r patch=$1
93    shift || usage "No patch file specified."
94    if [[ $BOUNCYCASTLE_BCPROV_PATCHES == *$patch* ]]; then
95      [ -d $BOUNCYCASTLE_BCPROV_DIR ] || usage "$BOUNCYCASTLE_BCPROV_DIR not found, did you mean to use generate?"
96      [ -d $BOUNCYCASTLE_BCPROV_DIR_ORIG ] || usage "$BOUNCYCASTLE_BCPROV_DIR_ORIG not found, did you mean to use generate?"
97      regenerate $patch $BOUNCYCASTLE_BCPROV_DIR $BOUNCYCASTLE_BCPROV_DIR_ORIG
98    elif [[ $BOUNCYCASTLE_BCPKIX_PATCHES == *$patch* ]]; then
99      [ -d $BOUNCYCASTLE_BCPKIX_DIR ] || usage "$BOUNCYCASTLE_BCPROV_DIR not found, did you mean to use generate?"
100      [ -d $BOUNCYCASTLE_BCPKIX_DIR_ORIG ] || usage "$BOUNCYCASTLE_BCPKIX_DIR_ORIG not found, did you mean to use generate?"
101      regenerate $patch $BOUNCYCASTLE_BCPKIX_DIR $BOUNCYCASTLE_BCPKIX_DIR_ORIG
102    else
103      usage "Unknown patch file $patch specified"
104    fi
105  elif [ "$command" = "generate" ]; then
106    declare -r patch=$1
107    shift || usage "No patch file specified."
108    declare -r bcprov_tar=$1
109    shift || usage "No tar file specified."
110    declare -r bcpkix_tar=`echo $bcprov_tar | sed s/bcprov/bcpkix/`
111    if [[ $BOUNCYCASTLE_BCPROV_PATCHES == *$patch* ]]; then
112      generate $patch $bcprov_tar $BOUNCYCASTLE_BCPROV_DIR $BOUNCYCASTLE_BCPROV_DIR_ORIG bcprov "$BOUNCYCASTLE_BCPROV_PATCHES" "$NEEDED_BCPROV_SOURCES" "$UNNEEDED_BCPROV_SOURCES"
113    elif [[ $BOUNCYCASTLE_BCPKIX_PATCHES == *$patch* ]]; then
114      generate $patch $bcpkix_tar $BOUNCYCASTLE_BCPKIX_DIR $BOUNCYCASTLE_BCPKIX_DIR_ORIG bcpkix "$BOUNCYCASTLE_BCPKIX_PATCHES" "$NEEDED_BCPKIX_SOURCES" "$UNNEEDED_BCPKIX_SOURCES"
115    else
116      usage "Unknown patch file $patch specified"
117    fi
118  else
119    usage "Unknown command specified $command. Try import, regenerate, or generate."
120  fi
121}
122
123function import() {
124  declare -r bouncycastle_source=$1
125  declare -r bouncycastle_dir=$2
126  declare -r bouncycastle_dir_orig=$3
127  declare -r bouncycastle_out_dir=$4
128  declare -r bouncycastle_patches=$5
129  declare -r needed_sources=$6
130  declare -r unneeded_sources=$7
131
132  untar $bouncycastle_source $bouncycastle_dir $bouncycastle_dir_orig "$unneeded_sources"
133  applypatches $bouncycastle_dir "$bouncycastle_patches" "$unneeded_sources"
134
135  cd $bouncycastle_dir
136
137  sed 's/<p>/& <BR>/g' LICENSE.html | html2text -width 102 -nobs -ascii > ../NOTICE
138  touch ../MODULE_LICENSE_BSD_LIKE
139
140  cd ..
141
142  rm -r $bouncycastle_out_dir/src
143  mkdir -p $bouncycastle_out_dir/src/main/java/
144  for i in $needed_sources; do
145    echo "Updating $i"
146    mv $bouncycastle_dir/$i $bouncycastle_out_dir/src/main/java/
147  done
148
149  cleantar $bouncycastle_dir $bouncycastle_dir_orig
150}
151
152function regenerate() {
153  declare -r patch=$1
154  declare -r bouncycastle_dir=$2
155  declare -r bouncycastle_dir_orig=$3
156
157  generatepatch $patch $bouncycastle_dir $bouncycastle_dir_orig
158}
159
160function update_timestamps() {
161  declare -r git_dir="$1"
162  declare -r target_dir="$2"
163
164  echo -n "Restoring timestamps for ${target_dir}... "
165
166  find "$git_dir" -type f -print0 | while IFS= read -r -d $'\0' file; do
167    file_rev="$(git rev-list -n 1 HEAD "$file")"
168    if [ "$file_rev" == "" ]; then
169      echo
170      echo -n "WARNING: No file revision for file $file..."
171      continue
172    fi
173    file_time="$(git show --pretty=format:%ai --abbrev-commit "$file_rev" | head -n 1)"
174    touch -d "$file_time" "${target_dir}${file#$git_dir}"
175  done
176
177  echo "done."
178}
179
180function generate() {
181  declare -r patch=$1
182  declare -r bouncycastle_source=$2
183  declare -r bouncycastle_dir=$3
184  declare -r bouncycastle_dir_orig=$4
185  declare -r bouncycastle_out_dir=$5
186  declare -r bouncycastle_patches=$6
187  declare -r needed_sources=$7
188  declare -r unneeded_sources=$8
189
190  untar $bouncycastle_source $bouncycastle_dir $bouncycastle_dir_orig "$unneeded_sources"
191  applypatches $bouncycastle_dir "$bouncycastle_patches" "$unneeded_sources"
192
193  for i in $needed_sources; do
194    echo "Restoring $i"
195    rm -r $bouncycastle_dir/$i
196    cp -rf $bouncycastle_out_dir/src/main/java/$i $bouncycastle_dir/$i
197    update_timestamps $bouncycastle_out_dir/src/main/java/$i $bouncycastle_dir/$i
198  done
199
200  generatepatch $patch $bouncycastle_dir $bouncycastle_dir_orig
201  cleantar $bouncycastle_dir $bouncycastle_dir_orig
202}
203
204function untar() {
205  declare -r bouncycastle_source=$1
206  declare -r bouncycastle_dir=$2
207  declare -r bouncycastle_dir_orig=$3
208  declare -r unneeded_sources=$4
209
210  # Remove old source
211  cleantar $bouncycastle_dir $bouncycastle_dir_orig
212
213  # Process new source
214  tar -zxf $bouncycastle_source
215  mv $bouncycastle_dir $bouncycastle_dir_orig
216  find $bouncycastle_dir_orig -type f -print0 | xargs -0 chmod a-w
217  (cd $bouncycastle_dir_orig && unzip -q src.zip)
218  tar -zxf $bouncycastle_source
219  (cd $bouncycastle_dir && unzip -q src.zip)
220
221  # Prune unnecessary sources
222  echo "Removing $unneeded_sources"
223  (cd $bouncycastle_dir_orig && rm -rf $unneeded_sources)
224  (cd $bouncycastle_dir      && rm -r  $unneeded_sources)
225
226  echo "Removing package.html files"
227  find $bouncycastle_dir_orig -name package.html -print0 | xargs -0 rm
228  find $bouncycastle_dir -name package.html -print0 | xargs -0 rm
229}
230
231function cleantar() {
232  declare -r bouncycastle_dir=$1
233  declare -r bouncycastle_dir_orig=$2
234
235  rm -rf $bouncycastle_dir_orig
236  rm -rf $bouncycastle_dir
237}
238
239function applypatches () {
240  declare -r bouncycastle_dir=$1
241  declare -r bouncycastle_patches=$2
242  declare -r unneeded_sources=$3
243
244  cd $bouncycastle_dir
245
246  # Apply appropriate patches
247  for i in $bouncycastle_patches; do
248    echo "Applying patch $i"
249    patch -p1 --merge < ../$i || die "Could not apply patches/$i. Fix source and run: $0 regenerate $i"
250
251    # make sure no unneeded sources got into the patch
252    problem=0
253    for s in $unneeded_sources; do
254      if [ -e $s ]; then
255        echo Unneeded source $s restored by patch $i
256        problem=1
257      fi
258    done
259    if [ $problem = 1 ]; then
260      exit 1
261    fi
262  done
263
264  # Cleanup patch output
265  find . -type f -name "*.orig" -print0 | xargs -0 rm -f
266
267  cd ..
268}
269
270function generatepatch() {
271  declare -r patch=$1
272  declare -r bouncycastle_dir=$2
273  declare -r bouncycastle_dir_orig=$3
274
275  # Cleanup stray files before generating patch
276  find $bouncycastle_dir -type f -name "*.orig" -print0 | xargs -0 rm -f
277  find $bouncycastle_dir -type f -name "*~" -print0 | xargs -0 rm -f
278
279  rm -f $patch
280  LC_ALL=C TZ=UTC0 diff -Naur $bouncycastle_dir_orig $bouncycastle_dir >> $patch && die "ERROR: No diff for patch $path in file $i"
281  echo "Generated patch $patch"
282}
283
284main $@
285