1#!/usr/bin/env bash
2
3###############################################################################
4#
5# Copyright (C) 2009-2013 Nintendo.  All rights reserved.
6#
7# These coded instructions, statements, and computer programs contain
8# proprietary information of Nintendo of America Inc. and/or Nintendo
9# Company Ltd., and are protected by Federal copyright law.  They may
10# not be disclosed to third parties or copied or duplicated in any form,
11# in whole or in part, without the prior written consent of Nintendo.
12#
13###############################################################################
14
15###############################################################################
16# main
17###############################################################################
18
19# Check arg
20if [ "$#" -ne 2 ]; then
21    echo "Usage: $0 AOC_ROOT_DIR AOC_NAME"
22    exit 1
23fi
24if [[ ! -d "$1" ]]; then
25    echo "[ERROR] $1 is not a directory!"
26    exit 1
27fi
28
29# Set variables
30AOC_ROOT_DIR=`cygpath -w -a "$1"`
31OUT_DIR="`cygpath -w -a "$AOC_ROOT_DIR"/outdir`"
32AOC_NAME="$2"
33APP_TITLE_ID=0005000C10000000
34APP_GROUP_ID=00000000
35APP_TITLE_VERSION=0000
36CAFE_BASEFILE_PATH="`cygpath -w "$CAFE_ROOT"/system/bin/tool/mastering/resources`"
37
38TOOL_DIR=`dirname "$0"`
39TOOL_DIR=`cygpath -w -a "$TOOL_DIR"`
40DEFAULT_DDF="`cygpath -w "$CAFE_ROOT"/system/bin/tool/mastering/resources/default_aoc.ddf`"
41COMMON_DDF_FILE="`cygpath -w "$OUT_DIR"/common_aoc.ddf`"
42INDIVIDUAL_DDF_FILE="`cygpath -w "$AOC_ROOT_DIR"/code/$AOC_NAME.ddf`"
43
44SECTION_ENTRY_HASH_OPTION="-filename_addhash"
45
46AOC_APP_XML="$AOC_ROOT_DIR/code/app.xml"
47AOC_COS_XML="$AOC_ROOT_DIR/code/cos.xml"
48AOC_META_XML="$AOC_ROOT_DIR/meta/meta.xml"
49META_DEFAULT_XML="$CAFE_ROOT/system/bin/ghs/cafe/boot/meta_default.xml"
50
51# Source function library.
52source "$TOOL_DIR/masteringfunctions.sh"
53
54
55###############################################################################
56# extract_info_from_app_xml
57# $1 - Path to app.xml
58###############################################################################
59extract_info_from_app_xml()
60{
61    arg_num_check $# 1
62    local APP_XML_FILE="$1"
63
64    # get title id
65    APP_TITLE_ID=`sed -n 's|.*<title_id .*>\(.*\)</.*>|\1|p' "$APP_XML_FILE"`
66    APP_GROUP_ID=`sed -n 's|.*<group_id .*>\(.*\)</.*>|\1|p' "$APP_XML_FILE"`
67    APP_TITLE_VERSION=`sed -n 's|.*<title_version .*>\(.*\)</.*>|\1|p' "$APP_XML_FILE"`
68
69    echo "App Title ID : $APP_TITLE_ID"
70    echo "App Group ID : $APP_GROUP_ID"
71    echo "App Title Version : $APP_TITLE_VERSION"
72}
73
74
75# Create directories, if not exist
76if [[ ! -e "$AOC_ROOT_DIR/code" ]]; then
77    mkdir "$AOC_ROOT_DIR/code"
78fi
79if [[ ! -e "$AOC_ROOT_DIR/meta" ]]; then
80    mkdir "$AOC_ROOT_DIR/meta"
81fi
82if [[ ! -e "$OUT_DIR" ]]; then
83    mkdir "$OUT_DIR"
84fi
85
86# Copy default xml files, if not exist
87if [[ ! -e "$AOC_APP_XML" ]]; then
88    cp $CAFE_ROOT/system/bin/ghs/cafe/boot/app_default.xml $AOC_APP_XML
89    # Replace the value in <app_type>: 80000000 -> 0800000E
90    sed -i -e "s|\(<app_type.*>\)\(.*\)\(</app_type.*>\)|\10800000E\3|" $AOC_APP_XML
91    # Replace the value in <title_id>: XXXXXXXXXXXXXXXX -> XXXXXXXCXXXXXXXX
92    sed -i -e "s|\(<title_id.*>\)\(.\{7\}\)\(.\)\(.\{8\}\)\(</title_id.*>\)|\1\2C\4\5|" $AOC_APP_XML
93#    sed -i -e "s|\(<title_id.*>\)\(.*\)\(</title_id.*>\)|\1XXXXXXXCXXXXXXXX\3|" $AOC_APP_XML
94fi
95if [[ ! -e "$AOC_COS_XML" ]]; then
96    cp $CAFE_ROOT/system/bin/ghs/cafe/boot/cos_default.xml $AOC_COS_XML
97fi
98if [[ ! -e "$AOC_META_XML" ]]; then
99    cp $CAFE_ROOT/system/bin/ghs/cafe/boot/meta_default.xml $AOC_META_XML
100fi
101
102# Copy default masterinfo.xml, if not exist
103DEFAULT_MASTERINFO_XML="$CAFE_ROOT/system/bin/tool/mastering/resources/masterinfo_aoc.xml"
104DEST_MASTERINFO_XML="$AOC_ROOT_DIR/code/masterinfo.xml"
105if [[ ! -e "$DEST_MASTERINFO_XML" ]]; then
106    cp -u "$DEFAULT_MASTERINFO_XML" "$DEST_MASTERINFO_XML"
107fi
108
109# Replace the GameType with "GA" (Game Add-on contents)
110sed -i -e "s|\(<GameType.*>\)\(.*\)\(</GameType.*>\)|\1GA\3|" "$DEST_MASTERINFO_XML"
111
112# Copy default iconTex.tga, if not exist
113DEFAULT_ICON_TEX_TGA="$CAFE_ROOT/system/bin/ghs/cafe/meta/iconTex.tga"
114DEST_ICON_TEX_TGA="$AOC_ROOT_DIR/meta/iconTex.tga"
115if [ ! -f "$DEST_ICON_TEX_TGA" ]; then
116    cp -u "$DEFAULT_ICON_TEX_TGA" "$DEST_ICON_TEX_TGA"
117fi
118
119# Call extract_info_from_app_xml
120extract_info_from_app_xml $AOC_APP_XML
121
122# set NDEBUG OS version
123G_OS_VERSION=`sed -n 's|.*<os_version.*>\(.*\)</os_version>|\1|p' "$META_DEFAULT_XML"`
124G_OS_VERSION=`echo $G_OS_VERSION | grep -Eo "[0-9a-fA-F]+"`
125if [ "${G_OS_VERSION:12:1}" == "8" ]; then
126    G_OS_VERSION="${G_OS_VERSION::12}4${G_OS_VERSION:13}"
127fi
128
129update_app_xml "$AOC_APP_XML"
130update_meta_xml "$AOC_META_XML"
131update_cos_xml "$AOC_COS_XML"
132
133check_appconf_version "$DEST_MASTERINFO_XML"
134
135# embed info
136# embed_sdk_version_to_masterinfo "$DEST_MASTERINFO_XML"
137embed_tool_version_to_masterinfo "$DEST_MASTERINFO_XML"
138embed_os_version_to_masterinfo "$DEST_MASTERINFO_XML"
139embed_mastering_sdk_version "$DEST_MASTERINFO_XML"
140reset_mastering_flag "$DEST_MASTERINFO_XML" "$AOC_META_XML"
141
142# Generate common_aoc.ddf
143echo "
144[Input]
145DiscHeaderBaseFileName=\"$CAFE_BASEFILE_PATH\\discheader_base.bin\"
146VolumeHeaderBaseFileName=\"$CAFE_BASEFILE_PATH\\volheader_base.bin\"
147
148[Output]
149LayoutFileName=\"$OUT_DIR\\$AOC_NAME.dlf\"
150OutputDirectory=\"$OUT_DIR\"
151AppName=\"$AOC_NAME\"
152
153[DiscID]
154GameType=GA
155TitleId=0x$APP_TITLE_ID
156GroupId=0x$APP_GROUP_ID
157GameVersion=`expr $(printf %d 0x$APP_TITLE_VERSION) / 16`
158
159[PathList]
160CODE_DIR=\"code\", \"$AOC_ROOT_DIR\\code\"
161META_DIR=\"meta\", \"$AOC_ROOT_DIR\\meta\"
162CONTENT_DIR=\"content\", \"$AOC_ROOT_DIR\\content\"
163" > "$COMMON_DDF_FILE"
164
165# Generate individual ddf file, if not exist
166if [[ ! -e $INDIVIDUAL_DDF_FILE ]]; then
167    echo "Generate individual_aoc.ddf"
168
169    # Get max section number
170    NUM_CONTENT_SUBDIR=`ls -1 "$AOC_ROOT_DIR/content" | wc -l`
171    (( MAX_SECTION = NUM_CONTENT_SUBDIR + 15 ))
172    if [[ ! -d "$AOC_ROOT_DIR/content/"`printf %04x $MAX_SECTION` ]]; then
173        echo "Error: $AOC_ROOT_DIR/content/`printf %04x $MAX_SECTION` not found"
174        exit 3
175    fi
176    echo "MAX_SECTION: `printf %04x $MAX_SECTION`"
177    if [[ $MAX_SECTION -ge 2016 ]]; then
178        echo "Error: Too many contents"
179        exit 4
180    fi
181
182    # Use hex number array instead of using printf, since printf is too slow
183    HEX_CHAR=(0 1 2 3 4 5 6 7 8 9 a b c d e f)
184    for (( i=0; i < 256; i++ )) {
185        (( hi = i / 16 ))
186        (( lo = i % 16 ))
187        HEX_STR[$i]="${HEX_CHAR[$hi]}${HEX_CHAR[$lo]}"
188    }
189
190    echo "Writing [SectionList]..."
191    {
192        echo "[SectionList]"
193        for (( i=0x0010; i<=MAX_SECTION; i++ )) {
194            (( hi = i / 256 ))
195            (( lo = i % 256 ))
196            SUBDIR_NAME="${HEX_STR[$hi]}${HEX_STR[$lo]}"
197
198            (( seclist_param = 100000 + 0x0010 - i ))
199            echo "\"ADDONCONTENT$SUBDIR_NAME\" = -$seclist_param"
200        }
201        echo ""
202    } >> "$INDIVIDUAL_DDF_FILE"
203
204    echo "Writing [SectionAssign]..."
205    {
206        echo "[SectionAssign]"
207        for (( i=0x0010; i<=MAX_SECTION; i++ )) {
208            (( hi = i / 256 ))
209            (( lo = i % 256 ))
210            SUBDIR_NAME="${HEX_STR[$hi]}${HEX_STR[$lo]}"
211
212            (( seclist_param = 100000 + 0x0010 - i ))
213            echo "-$seclist_param = \"content/$SUBDIR_NAME/*\", \"ADDONCONTENT$SUBDIR_NAME\", 0x040"
214        }
215        echo ""
216    } >> "$INDIVIDUAL_DDF_FILE"
217
218    echo "Writing [SectionParam]..."
219    {
220        echo "[SectionParam]"
221        echo "\"CONTENTDIR\" = 0x0000000000000000, 0x$APP_GROUP_ID, 0x02"
222        for (( i=0x0010; i<=MAX_SECTION; i++ )) {
223            (( hi = i / 256 ))
224            (( lo = i % 256 ))
225            SUBDIR_NAME="${HEX_STR[$hi]}${HEX_STR[$lo]}"
226
227            echo "\"ADDONCONTENT$SUBDIR_NAME\" = 0x0000000000000000, 0x$APP_GROUP_ID, 0x02"
228        }
229        echo ""
230    } >> "$INDIVIDUAL_DDF_FILE"
231else
232    cd $AOC_ROOT_DIR
233    # Force replace the GameType with "GA" (Game Add-on contents)
234
235    sed -i -e "s|\(GameType *= *\).*|\1GA|" "$INDIVIDUAL_DDF_FILE"
236
237    # Force replace the permission of ADDONCONTENT section with 0x040
238    sed -i -e "s|\(-[0-9]* *= *\"content/[0-9A-Fa-f]\{4\}/\*\", *\"ADDONCONTENT[0-9A-Fa-f]\{4\}\", *0x\)[0-9]\{3\}|\1040|" "$INDIVIDUAL_DDF_FILE"
239
240    # Force replace the OwnerId of ADDONCONTENT section with 0x0000000000000000
241    APP_GROUP_ID=`sed -n 's|\"ADDONCONTENT0010\" *= *0x[0-9A-Fa-f]*, *0x\([0-9A-Fa-f]*\), *0x[0-9A-Fa-f]*|\1|p' "$INDIVIDUAL_DDF_FILE"`
242    sed -i -e "/\"CONTENTDIR\" *= *0x[0-9A-Fa-f]*, *0x[0-9A-Fa-f]*, *0x[0-9A-Fa-f]*/d" "$INDIVIDUAL_DDF_FILE"
243    sed -i -e "s|\[SectionParam\]|\[SectionParam\]\n\"CONTENTDIR\" = 0x0000000000000000, 0x$APP_GROUP_ID, 0x02|" "$INDIVIDUAL_DDF_FILE"
244    sed -i -e "s|\(\"ADDONCONTENT[0-9A-Fa-f]\{4\}\" *= *\)0x[0-9A-Fa-f]*\(, *0x[0-9A-Fa-f]*, *0x[0-9A-Fa-f]*\)|\10x0000000000000000\2|" "$INDIVIDUAL_DDF_FILE"
245    cd -
246fi
247
248embed_ddf_info_to_masterinfo "$INDIVIDUAL_DDF_FILE" "$DEST_MASTERINFO_XML"
249check_section_entry_hash
250update_xml_flag_section_entry_hash "$DEST_MASTERINFO_XML" "$AOC_META_XML"
251
252"$MAKEDLF" -uf -mss=4024 -mi="$DEST_MASTERINFO_XML" "$DEFAULT_DDF" "$COMMON_DDF_FILE" "$INDIVIDUAL_DDF_FILE" "$SECTION_ENTRY_HASH_OPTION"
253
254"$MAKEIDBE" "$AOC_ROOT_DIR\\code\\masterinfo.xml" "$AOC_ROOT_DIR\\meta\\iconTex.tga" "$OUT_DIR\\icon.db"
255
256"$MAKEMASTER" -v -nc "-wd=./workdir" "$OUT_DIR\\$AOC_NAME.dlf" "$CAFE_BASEFILE_PATH\\masterheader_base.bin" "$AOC_ROOT_DIR\\code\\masterinfo.xml" "$OUT_DIR\\$AOC_NAME.wumad" "-rl=$OUT_DIR\\icon.db" "$SECTION_ENTRY_HASH_OPTION"
257
258# Show messages
259show_msg
260
261rm -Rf "./workdir"
262
263exit 0
264