Merge: nitcatalog: isolate package page into a subdirectory
authorJean Privat <jean@pryen.org>
Tue, 15 Sep 2015 19:18:38 +0000 (15:18 -0400)
committerJean Privat <jean@pryen.org>
Tue, 15 Sep 2015 19:18:38 +0000 (15:18 -0400)
HTML files are generated into a `/p/` subdirectory so they will not conflict with other generated files.

One other point is to have stable and final URL for packages in the catalog. eg http://nitlanguage.org/catalog/p/nitiwiki.html

Pull-Request: #1714
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

39 files changed:
contrib/crazy_moles/Makefile
contrib/friendz/Makefile
contrib/mnit_test/Makefile
contrib/opportunity/src/opportunity_controller.nit
contrib/opportunity/src/opportunity_model.nit
contrib/tinks/Makefile
contrib/tinks/art/icon.svg
examples/calculator/art/icon.svg
examples/mnit_ballz/Makefile
examples/mnit_dino/Makefile
examples/rosettacode/sha_1.nit
examples/shoot/Makefile
lib/base64.nit
lib/core/bytes.nit
lib/core/stream.nit
lib/core/text/flat.nit
lib/gamnit/display.nit [new file with mode: 0644]
lib/gamnit/display_android.nit [new file with mode: 0644]
lib/gamnit/display_linux.nit [new file with mode: 0644]
lib/gamnit/egl.nit [new file with mode: 0644]
lib/gamnit/examples/triangle/Makefile [new file with mode: 0644]
lib/gamnit/examples/triangle/art/icon.svg [new file with mode: 0644]
lib/gamnit/examples/triangle/bin/.gitignore [new file with mode: 0644]
lib/gamnit/examples/triangle/package.ini [new file with mode: 0644]
lib/gamnit/examples/triangle/res/.gitignore [new file with mode: 0644]
lib/gamnit/examples/triangle/src/portable_triangle.nit [new file with mode: 0644]
lib/gamnit/examples/triangle/src/standalone_triangle.nit [new file with mode: 0644]
lib/gamnit/gamnit.nit
lib/gamnit/gamnit_android.nit [new file with mode: 0644]
lib/linux/linux.nit
lib/mnit/linux/linux_app.nit
lib/sha1.nit
lib/websocket/websocket.nit
src/compiler/compiler_ffi/compiler_ffi.nit
tests/sav/nitcg/test_text_stat.res
tests/sav/nitserial_args1.res
tests/sav/test_bytes_hexdigit.res [new file with mode: 0644]
tests/sav/test_text_stat.res
tests/test_bytes_hexdigit.nit [new file with mode: 0644]

index 3fc90f7..049e851 100644 (file)
@@ -4,11 +4,14 @@ bin/moles: $(shell ../../bin/nitls -M src/moles_linux.nit) assets/images/drawing
        mkdir -p bin
        ../../bin/nitc -o bin/moles src/moles_linux.nit
 
+android: bin/moles.apk
 bin/moles.apk: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png
        mkdir -p bin
        ../../bin/nitc -o bin/moles.apk src/moles_android.nit
 
-android: bin/moles.apk
+android-release: android-icons $(shell ../../bin/nitls -M src/moles_android.nit) assets/images/drawing.png
+       mkdir -p bin
+       ../../bin/nitc -o bin/moles.apk src/moles_android.nit --release
 
 ../inkscape_tools/bin/svg_to_icons:
        $(MAKE) -C ../inkscape_tools
index f236a1d..0cedb4c 100644 (file)
@@ -4,11 +4,18 @@ linux:
        mkdir -p bin
        ../../bin/nitc -o bin/friendz src/friendz_linux.nit
 
-android:
-       mkdir -p bin res
-       ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+android: res/drawable-hdpi/icon.png
+       mkdir -p bin
        ../../bin/nitc -o bin/friendz.apk src/friendz_android.nit
 
+android-release: res/drawable-hdpi/icon.png
+       mkdir -p bin
+       ../../bin/nitc -o bin/friendz.apk src/friendz_android.nit --release
+
+res/drawable-hdpi/icon.png: art/icon.svg
+       mkdir -p res
+       ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+
 doc:
        mkdir -p doc
        ../../bin/nitdoc -d doc/ src/friendz.nit src/friendz_linux.nit
index 73ed663..a198c27 100644 (file)
@@ -9,5 +9,10 @@ android:
        ../../bin/nitc -o bin/complete.apk src/complete_simple_android.nit --semi-global
        ../../bin/nitc -o bin/minimal.apk src/simple_android.nit --semi-global
 
+android-release:
+       mkdir -p bin
+       ../../bin/nitc -o bin/complete.apk src/complete_simple_android.nit --semi-global --release
+       ../../bin/nitc -o bin/minimal.apk src/simple_android.nit --semi-global --release
+
 clean:
        rm -rf bin
index 868dd9e..26a4ef6 100644 (file)
@@ -16,7 +16,6 @@
 module opportunity_controller
 
 import nitcorn
-import sha1
 import templates
 import opportunity_model
 
index ef7654d..cc72f23 100644 (file)
@@ -247,7 +247,7 @@ class Meetup
        redef fun commit(db) do
                if id == "" then
                        var time = get_time
-                       var tmpid = (name + date + place + time.to_s).sha1_to_s
+                       var tmpid = (name + date + place + time.to_s).sha1.hexdigest
                        if not db.execute("INSERT INTO meetups (id, name, date, place, answer_mode) VALUES({tmpid.to_sql_string}, {name.html_escape.to_sql_string}, {date.html_escape.to_sql_string}, {place.html_escape.to_sql_string}, {answer_mode});") then
                                print "Error recording entry Meetup {self}"
                                print db.error or else "Null error"
index b22453a..ee13360 100644 (file)
@@ -32,9 +32,12 @@ src/server/server_serialize.nit: $(shell ../../bin/nitls -M src/server/dedicated
        ../../bin/nitserial -o src/server/server_serialize.nit src/server/dedicated.nit
 
 # Android
+android: bin/tinks.apk
 bin/tinks.apk: assets/images/drawing.png src/client/client_serialize.nit res/drawable-ldpi/icon.png $(shell ../../bin/nitls -M src/client/android_client.nit)
-       ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit --compile-dir nit_compile
-       adb install -r bin/tinks.apk
+       ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit
+
+android-release: assets/images/drawing.png src/client/client_serialize.nit res/drawable-ldpi/icon.png $(shell ../../bin/nitls -M src/client/android_client.nit)
+       ../../bin/nitc -o bin/tinks.apk src/client/android_client.nit -m src/client/client_serialize.nit --release
 
 res/drawable-ldpi/icon.png: art/icon.svg
        ../inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
index 20a590d..32229e4 100644 (file)
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="1.979899"
-     inkscape:cx="107.98668"
-     inkscape:cy="65.759563"
+     inkscape:cx="357.89925"
+     inkscape:cy="19.247995"
      inkscape:document-units="px"
      inkscape:current-layer="0splash"
      showgrid="false"
          transform="matrix(0.9571749,0,0,0.9571749,14.241487,126.08446)">
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
-           d="m 258.625,595.8125 c -4.89966,1.4313 -12.56953,-1.70866 -15.1875,4.5625 -0.4775,5.90634 -3.5509,14.50575 2.71875,18.6875 2.28891,1.18746 5.12,1.54986 7.5625,0.59375 0.52227,3.72431 1.0541,7.99473 -2.03125,10.59375 -3.51238,6.69348 3.86364,14.87896 10.90625,12.96875 6.54546,1.2404 16.20527,-0.87285 16.34375,-9 1.15076,-4.65522 -4.58661,-6.69297 -3.46875,-11.1875 -0.95739,-2.94159 3.31489,-1.69978 4.46875,-3.78125 5.83868,-2.11249 5.55685,-9.07334 5.53125,-14.34375 1.81324,-6.47371 -5.8435,-9.85183 -11.15625,-8.5625 -4.34595,0.15294 -9.06169,-1.83389 -13.21875,-0.125 0.0516,-2.21144 -1.36209,-0.68823 -2.46875,-0.40625 z"
+           d="m 258.625,595.8125 c -4.89966,1.4313 -12.56953,-1.70866 -15.1875,4.5625 -0.4775,5.90634 -3.5509,14.50575 2.71875,18.6875 2.28891,1.18746 5.12,1.54986 7.5625,0.59375 0.52227,3.72431 1.0541,7.99473 -2.03125,10.59375 -3.51238,6.69348 3.86364,14.87896 10.90625,12.96875 6.54546,1.2404 16.20527,-0.87285 16.34375,-9 1.15076,-4.65522 0.20769,-5.09487 1.32555,-9.5894 -0.95739,-2.94159 -1.47941,-3.29788 -0.32555,-5.37935 5.83868,-2.11249 5.55685,-9.07334 5.53125,-14.34375 1.81324,-6.47371 -5.8435,-9.85183 -11.15625,-8.5625 -4.34595,0.15294 -9.06169,-1.83389 -13.21875,-0.125 0.0516,-2.21144 -1.36209,-0.68823 -2.46875,-0.40625 z"
            id="path3211"
-           inkscape:connector-curvature="0" />
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccccccccccccc" />
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
            d="m 286.25,592.6875 c -2.39783,0.63195 -3.74457,2.90332 -6.59375,2.8125 -5.4632,2.29227 -6.35616,10.35289 -2.0625,14.25 -0.60542,4.15669 0.70607,8.39731 0.4375,12.3125 -0.0599,3.57375 -1.98208,6.31549 -3.3125,9.34375 -1.62554,5.38708 2.55698,12.80186 8.96875,10.96875 6.47834,0.22337 16.30714,2.49861 19.125,-5.53125 1.23942,-3.73894 -0.38135,-7.90712 -3.59375,-10.09375 0.3082,-5.37065 -0.71586,-11.3191 0.59375,-16.375 6.74005,-4.69817 1.76294,-18.17585 -6.625,-15.0625 -2.79844,0.69065 -4.06188,-3.31293 -6.9375,-2.625 z"
            inkscape:connector-curvature="0" />
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
-           d="m 362.71875,595.53125 c -4.88629,0.1191 -10.06204,0.70685 -14.78125,0.75 -5.47787,-0.76679 -11.36437,-0.40783 -16.78125,-0.15625 -5.17104,2.08849 -5.75771,9.90066 -1.65625,13.3125 -0.73815,5.29915 0.55713,11.35287 -0.28125,16.21875 -1.57391,2.43976 0.0174,5.43494 -1.9375,7.65625 -1.21338,8.01052 8.60308,12.27891 15.15625,10.1875 4.10866,1.15111 8.03361,-0.96492 11.90625,0.75 4.70244,-0.0919 9.41322,-0.76127 13.9375,-1.21875 6.34357,-2.47232 7.27867,-12.62071 1.1875,-15.90625 -2.84504,-3.85906 -6.71699,-8.25024 -7.5,-12.8125 2.57537,-4.33547 10.38664,-3.74912 10.125,-10.0625 0.19504,-4.87459 -4.47645,-9.43549 -9.375,-8.71875 z"
+           d="m 362.71875,595.53125 c -4.88629,0.1191 -10.06204,0.70685 -14.78125,0.75 -5.47787,-0.76679 -11.36437,-0.40783 -16.78125,-0.15625 -5.17104,2.08849 -5.75771,9.90066 -1.65625,13.3125 -0.73815,5.29915 0.55713,11.35287 -0.28125,16.21875 -1.57391,2.43976 0.0174,5.43494 -1.9375,7.65625 -1.21338,8.01052 8.60308,12.27891 15.15625,10.1875 4.10866,1.15111 8.03361,-0.96492 11.90625,0.75 4.70244,-0.0919 9.41322,-0.76127 13.9375,-1.21875 6.34357,-2.47232 7.27867,-12.62071 1.1875,-15.90625 -2.84504,-3.85906 -3.69836,-8.25024 -4.48137,-12.8125 2.57537,-4.33547 7.36801,-3.74912 7.10637,-10.0625 0.19504,-4.87459 -4.47645,-9.43549 -9.375,-8.71875 z"
            id="path3217"
-           inkscape:connector-curvature="0" />
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="ccccccccccccc" />
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
            d="m 387.9375,595.15625 c -4.67722,2.02978 -9.78906,-1.62403 -14.46875,1.25 -9.65979,4.02935 -13.06716,17.5954 -7.09375,25.71875 -5.60204,3.65765 -3.86108,11.71823 -2.5625,17.15625 1.89135,4.23664 7.4795,4.74734 11.125,3.125 3.94271,1.07416 7.9082,-0.0824 11.78125,1.1875 12.90654,0.16282 22.05847,-17.35307 13.34375,-27.46875 4.21701,-4.46396 3.58479,-12.34862 1.53125,-17.90625 -3.12179,-4.23683 -8.89538,-1.69513 -13.1875,-3.09375 l -0.46875,0.0312 z"
            inkscape:connector-curvature="0" />
         <path
            style="font-size:52.50814056px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-1px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle"
-           d="m 413.09375,593.625 c -5.989,0.79809 -12.31873,3.77439 -13.59375,10.28125 -2.37552,6.92367 2.58427,13.98287 3.0625,20.28125 -6.66505,6.69348 -1.32209,20.82556 8.75,19.25 7.10297,0.39661 12.84047,-7.75209 9.8125,-14.21875 0.3156,-2.89071 -3.70654,-4.76237 -1.46875,-7.53125 2.44848,-7.39695 6.24638,-18.36454 -1.53125,-23.75 -0.23875,-2.6484 -2.19852,-4.85675 -5.03125,-4.3125 z"
+           d="m 413.09375,593.625 c -5.989,0.79809 -12.31873,3.77439 -13.59375,10.28125 -2.77433,6.83505 1.00514,13.63195 3.0625,20.28125 -6.66505,6.69348 -1.32209,20.82556 8.75,19.25 7.10297,0.39661 12.84047,-7.75209 9.8125,-14.21875 0.3156,-2.89071 -3.70654,-4.76237 -1.46875,-7.53125 2.44848,-7.39695 6.24638,-18.36454 -1.53125,-23.75 -0.23875,-2.6484 -2.19852,-4.85675 -5.03125,-4.3125 z"
            id="path3221"
-           inkscape:connector-curvature="0" />
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccccccc" />
       </g>
       <g
          style="stroke:#000000;stroke-width:3.85294461;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
            x="251.05626"
            id="tspan2996"
            sodipodi:role="line">TINKS!</tspan></text>
+      <text
+         xml:space="preserve"
+         style="font-size:50.25947571px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e6e6e6;fill-opacity:1;stroke:none;font-family:Sans"
+         x="251.05626"
+         y="809.98505"
+         id="text3032"
+         sodipodi:linespacing="125%"><tspan
+           sodipodi:role="line"
+           id="tspan3034"
+           x="251.05626"
+           y="809.98505"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;letter-spacing:-0.9571749px;fill:#e6e6e6;fill-opacity:1;font-family:Armalite Rifle;-inkscape-font-specification:Armalite Rifle">TINKS!</tspan></text>
     </g>
   </g>
 </svg>
index ccd533c..618dc3d 100644 (file)
@@ -24,9 +24,9 @@
      borderopacity="1.0"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="0.9899495"
-     inkscape:cx="58.64005"
-     inkscape:cy="380.00465"
+     inkscape:zoom="1.4"
+     inkscape:cx="160.56125"
+     inkscape:cy="282.40083"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="false"
        width="211.42856"
        id="rect2995"
        style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
-    <text
-       xml:space="preserve"
+    <g
        style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
-       x="299.74573"
-       y="770.06946"
-       id="text2997"
-       sodipodi:linespacing="125%"><tspan
-         sodipodi:role="line"
-         id="tspan2999"
-         x="299.74573"
-         y="770.06946">+</tspan></text>
+       id="text2997">
+      <path
+         d="m 364.00188,685.0516 -50.85303,0 0,-19.71047 50.85303,0 0,-51.11584 19.71048,0 0,51.11584 50.85303,0 0,19.71047 -50.85303,0 0,50.59023 -19.71048,0 0,-50.59023"
+         style=""
+         id="path2996" />
+    </g>
     <path
        inkscape:connector-curvature="0"
        id="path3018"
        id="path2997"
        style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
        d="m 179.68975,735.88154 c -1e-5,-2.50244 0.32926,-4.60977 0.98782,-6.32199 0.65852,-1.77805 1.54755,-3.19391 2.66709,-4.2476 1.1195,-1.11949 2.43658,-1.90974 3.95125,-2.37074 1.51462,-0.52681 3.16097,-0.79023 4.93905,-0.79025 1.71218,2e-5 3.32561,0.26344 4.84028,0.79025 1.58047,0.461 2.93048,1.25125 4.05003,2.37074 1.11948,1.05369 2.00851,2.46955 2.66709,4.2476 0.65851,1.71222 0.98778,3.81955 0.98782,6.32199 -4e-5,2.43661 -0.32931,4.54394 -0.98782,6.322 -0.65858,1.71221 -1.54761,3.12807 -2.66709,4.24759 -1.11955,1.11952 -2.46956,1.94269 -4.05003,2.46953 -1.51467,0.52683 -3.1281,0.79024 -4.84028,0.79025 -1.77808,-10e-6 -3.42443,-0.26342 -4.93905,-0.79025 -1.51467,-0.52684 -2.83175,-1.35001 -3.95125,-2.46953 -1.11954,-1.11952 -2.00857,-2.53538 -2.66709,-4.24759 -0.65856,-1.77806 -0.98783,-3.88539 -0.98782,-6.322" />
-    <text
-       xml:space="preserve"
+    <g
        style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
-       x="64.031456"
-       y="1006.8839"
-       id="text3013"
-       sodipodi:linespacing="125%"><tspan
-         sodipodi:role="line"
-         id="tspan3015"
-         x="64.031456"
-         y="1006.8839">=</tspan></text>
+       id="text3013">
+      <path
+         d="m 77.43458,894.9284 0,-19.57907 121.41654,0 0,19.57907 -121.41654,0 m 0,53.87531 0,-19.71048 121.41654,0 0,19.71048 -121.41654,0"
+         style=""
+         id="path2999" />
+    </g>
   </g>
 </svg>
index 4120b52..b9a0dfc 100644 (file)
@@ -7,6 +7,10 @@ android: icon
        mkdir -p bin
        ../../bin/nitc -o bin/ballz.apk src/ballz_android.nit
 
+android-release: icon
+       mkdir -p bin
+       ../../bin/nitc -o bin/ballz.apk src/ballz_android.nit --release
+
 linux:
        mkdir -p bin
        ../../bin/nitc -o bin/ballz src/ballz_linux.nit
index 42364bf..14faa98 100644 (file)
@@ -8,6 +8,10 @@ android: android-icons
        mkdir -p bin
        ../../bin/nitc -o bin/dino.apk src/dino_android.nit
 
+android-release: android-icons
+       mkdir -p bin
+       ../../bin/nitc -o bin/dino.apk src/dino_android.nit --release
+
 ../../contrib/inkscape_tools/bin/svg_to_icons:
        $(MAKE) -C ../../contrib/inkscape_tools
 
index 2eaf471..8776d48 100644 (file)
@@ -9,4 +9,4 @@ module sha_1
 
 import sha1
 
-print "Rosetta Code".sha1_to_s
+print "Rosetta Code".sha1.hexdigest
index 5e564d7..a42ffde 100644 (file)
@@ -8,6 +8,10 @@ android:
        mkdir -p bin
        ../../bin/nitc -o bin/shoot.apk src/shoot_android.nit
 
+android-release:
+       mkdir -p bin
+       ../../bin/nitc -o bin/shoot.apk src/shoot_android.nit --release
+
 null:
        mkdir -p bin
        ../../bin/nitc -o bin/shoot_null src/shoot_null.nit
index 5f1c920..4eae395 100644 (file)
 # Offers the base 64 encoding and decoding algorithms
 module base64
 
-redef class String
-
+redef class NativeString
        # Alphabet used by the base64 algorithm
-       private fun base64_chars : String
+       private fun base64_chars : SequenceRead[Byte]
        do
-               return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+               return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".bytes
        end
+
+       # Reversed alphabet for base64
        private fun inverted_base64_chars : HashMap[Byte, Byte]
        do
                var inv_base64_chars = new HashMap[Byte, Byte]
-               for k in [0..base64_chars.bytelen[ do
-                       inv_base64_chars[base64_chars.bytes[k]] = k.to_b
+               var l = base64_chars.length
+               for k in [0 .. l[ do
+                       inv_base64_chars[base64_chars[k]] = k.to_b
                end
                return inv_base64_chars
        end
 
-       # Encodes the receiver string to base64.
+       # Encodes `self` to base64.
+       #
        # By default, uses "=" for padding.
-       fun encode_base64 : String do return encode_base64_custom_padding('='.ascii.to_b)
-
-       # Encodes the receiver string to base64 using a custom padding character.
        #
-       # If using the default padding character `=`, see `encode_base64`.
-       fun encode_base64_custom_padding(padding : Byte) : String
-       do
-               var base64_bytes = once base64_chars.bytes
-               var length = bytelen
-
+       #     assert "string".encode_base64 == "c3RyaW5n"
+       private fun encode_base64(length: Int, padding: nullable Byte): Bytes do
+               var base64_bytes = once base64_chars
+               if padding == null then padding = '='.ascii.to_b
                var steps = length / 3
                var bytes_in_last_step = length % 3
                var result_length = steps * 4
                if bytes_in_last_step > 0 then result_length += 4
-               var result = new NativeString(result_length + 1)
-               var bytes = self.bytes
-               result[result_length] = 0u8
-
-               var mask_6bit = 0b0011_1111
+               var result = new Bytes.with_capacity(result_length)
 
+               var in_off = 0
                for s in [0 .. steps[ do
-                       var e = 0
-                       for ss in [0 .. 3[ do
-                               e += bytes[s * 3 + ss].to_i << ((2 - ss) * 8)
-                       end
-                       for ss in [0..4[ do
-                               result[s * 4 + 3 - ss] = base64_bytes[(e >> (ss * 6)) & mask_6bit]
-                       end
+                       var ind = ((self[in_off] & 0b1111_1100u8) >> 2).to_i
+                       result.add base64_bytes[ind]
+                       ind = ((self[in_off] & 0b0000_0011u8) << 4).to_i | ((self[in_off + 1] & 0b1111_0000u8) >> 4).to_i
+                       result.add base64_bytes[ind]
+                       ind = ((self[in_off + 1] & 0b0000_1111u8) << 2).to_i | ((self[in_off + 2] & 0b1100_0000u8) >> 6).to_i
+                       result.add base64_bytes[ind]
+                       ind = (self[in_off + 2] & 0b0011_1111u8).to_i
+                       result.add base64_bytes[ind]
+                       in_off += 3
                end
-
-               var out_off = result_length - 4
-               var in_off = length - bytes_in_last_step
                if bytes_in_last_step == 1 then
-                       result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i]
-                       result[out_off + 1] = base64_bytes[((bytes[in_off] & 0b0000_0011u8) << 4).to_i]
-                       out_off += 2
+                       result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i]
+                       result.add base64_bytes[((self[in_off] & 0b0000_0011u8) << 4).to_i]
                else if bytes_in_last_step == 2 then
-                       result[out_off] = base64_bytes[((bytes[in_off] & 0b1111_1100u8) >> 2).to_i]
-                       result[out_off + 1] = base64_bytes[(((bytes[in_off] & 0b0000_0011u8) << 4) | ((bytes[in_off + 1] & 0b1111_0000u8) >> 4)).to_i]
-                       result[out_off + 2] = base64_bytes[((bytes[in_off + 1] & 0b0000_1111u8) << 2).to_i]
-                       out_off += 3
-               end
-               if bytes_in_last_step > 0 then
-                       for i in [out_off .. result_length[ do result[i] = padding
+                       result.add base64_bytes[((self[in_off] & 0b1111_1100u8) >> 2).to_i]
+                       result.add base64_bytes[(((self[in_off] & 0b0000_0011u8) << 4) | ((self[in_off + 1] & 0b1111_0000u8) >> 4)).to_i]
+                       result.add base64_bytes[((self[in_off + 1] & 0b0000_1111u8) << 2).to_i]
                end
+               var rempad = if bytes_in_last_step > 0 then 3 - bytes_in_last_step else 0
+               for i in [0 .. rempad[ do result.add padding
 
-               return result.to_s_with_length(result_length)
+               return result
        end
 
-       # Decodes the receiver string from base64.
-       # By default, uses "=" for padding.
-       fun decode_base64 : String do return decode_base64_custom_padding('='.ascii.to_b)
-
-       # Decodes the receiver string to base64 using a custom padding character.
+       # Decodes `self` from base64
        #
-       # If using the default padding character `=`, see `decode_base64`.
-       fun decode_base64_custom_padding(padding : Byte) : String
-       do
+       #      assert "c3RyaW5n".decode_base64 == "string"
+       #
+       # REQUIRE: `length % 4 == 0`
+       private fun decode_base64(length: Int, padding: nullable Byte): Bytes do
+               if padding == null then padding = '='.ascii.to_b
                var inv = once inverted_base64_chars
-               var length = bytelen
-               if length == 0 then return ""
+               if length == 0 then return new Bytes.empty
                assert length % 4 == 0 else print "base64::decode_base64 only supports strings of length multiple of 4"
 
-               var bytes = self.bytes
+               var bytes = self
                var steps = length / 4
                var result_length = steps * 3
 
@@ -113,17 +101,16 @@ redef class String
                if padding_len == 1 then result_length -= 1
                if padding_len == 2 then result_length -= 2
 
-               var result = new NativeString(result_length + 1)
-               result[result_length] = 0u8
+               var result = new Bytes.with_capacity(result_length + 1)
 
                for s in [0 .. steps[ do
                        var c0 = inv[bytes[s * 4]]
                        var c1 = inv[bytes[s * 4 + 1]]
                        var c2 = inv[bytes[s * 4 + 2]]
                        var c3 = inv[bytes[s * 4 + 3]]
-                       result[s * 3] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
-                       result[s * 3 + 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)
-                       result[s * 3 + 2] = ((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8)
+                       result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
+                       result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2))
+                       result.add (((c2 & 0b0000_0011u8) << 6) | (c3 & 0b0011_1111u8))
                end
 
                var last_start = steps * 4
@@ -131,14 +118,52 @@ redef class String
                        var c0 = inv[bytes[last_start]]
                        var c1 = inv[bytes[last_start + 1]]
                        var c2 = inv[bytes[last_start + 2]]
-                       result[result_length - 2] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
-                       result[result_length - 1] = ((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2)
+                       result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
+                       result.add (((c1 & 0b0000_1111u8) << 4) | ((c2 & 0b0011_1100u8) >> 2))
                else if padding_len == 2 then
                        var c0 = inv[bytes[last_start]]
                        var c1 = inv[bytes[last_start + 1]]
-                       result[result_length - 1] = ((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4)
+                       result.add (((c0 & 0b0011_1111u8) << 2) | ((c1 & 0b0011_0000u8) >> 4))
                end
 
-               return result.to_s_with_length(result_length)
+               return result
+       end
+end
+
+redef class Bytes
+
+       # Encodes the receiver string to base64 using a custom padding character.
+       #
+       # If using the default padding character `=`, see `encode_base64`.
+       fun encode_base64(padding: nullable Byte): Bytes
+       do
+               return items.encode_base64(length, padding)
+       end
+
+       # Decodes the receiver string to base64 using a custom padding character.
+       #
+       # Default padding character `=`
+       fun decode_base64(padding : nullable Byte) : Bytes
+       do
+               return items.decode_base64(length, padding)
+       end
+end
+
+redef class String
+
+       # Encodes the receiver string to base64 using a custom padding character.
+       #
+       # If using the default padding character `=`, see `encode_base64`.
+       fun encode_base64(padding: nullable Byte): String
+       do
+               return to_cstring.encode_base64(bytelen, padding).to_s
+       end
+
+       # Decodes the receiver string to base64 using a custom padding character.
+       #
+       # Default padding character `=`
+       fun decode_base64(padding : nullable Byte) : String
+       do
+               return to_cstring.decode_base64(bytelen, padding).to_s
        end
 end
index 59c4c5f..356f386 100644 (file)
@@ -19,6 +19,61 @@ import kernel
 import collection::array
 intrude import text::flat
 
+redef class Byte
+       # Write self as a string into `ns` at position `pos`
+       private fun add_digest_at(ns: NativeString, pos: Int) do
+               var tmp = (0xF0u8 & self) >> 4
+               ns[pos] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8
+               tmp = 0x0Fu8 & self
+               ns[pos + 1] = if tmp >= 0x0Au8 then tmp + 0x37u8 else tmp + 0x30u8
+       end
+
+       # Is `self` a valid hexadecimal digit (in ASCII)
+       #
+       # ~~~nit
+       # intrude import core::bytes
+       # assert not '/'.ascii.to_b.is_valid_hexdigit
+       # assert '0'.ascii.to_b.is_valid_hexdigit
+       # assert '9'.ascii.to_b.is_valid_hexdigit
+       # assert not ':'.ascii.to_b.is_valid_hexdigit
+       # assert not '@'.ascii.to_b.is_valid_hexdigit
+       # assert 'A'.ascii.to_b.is_valid_hexdigit
+       # assert 'F'.ascii.to_b.is_valid_hexdigit
+       # assert not 'G'.ascii.to_b.is_valid_hexdigit
+       # assert not '`'.ascii.to_b.is_valid_hexdigit
+       # assert 'a'.ascii.to_b.is_valid_hexdigit
+       # assert 'f'.ascii.to_b.is_valid_hexdigit
+       # assert not 'g'.ascii.to_b.is_valid_hexdigit
+       # ~~~
+       private fun is_valid_hexdigit: Bool do
+               return (self >= 0x30u8 and self <= 0x39u8) or
+                      (self >= 0x41u8 and self <= 0x46u8) or
+                      (self >= 0x61u8 and self <= 0x66u8)
+       end
+
+       # `self` as a hexdigit to its byte value
+       #
+       # ~~~nit
+       # intrude import core::bytes
+       # assert 0x39u8.hexdigit_to_byteval == 0x09u8
+       # assert 0x43u8.hexdigit_to_byteval == 0x0Cu8
+       # ~~~
+       #
+       # REQUIRE: `self.is_valid_hexdigit`
+       private fun hexdigit_to_byteval: Byte do
+               if self >= 0x30u8 and self <= 0x39u8 then
+                       return self - 0x30u8
+               else if self >= 0x41u8 and self <= 0x46u8 then
+                       return self - 0x37u8
+               else if self >= 0x61u8 and self <= 0x66u8 then
+                       return self - 0x57u8
+               end
+               # Happens only if the requirement is not met.
+               # i.e. this abort is here to please the compiler
+               abort
+       end
+end
+
 # A buffer containing Byte-manipulation facilities
 #
 # Uses Copy-On-Write when persisted
@@ -26,7 +81,7 @@ class Bytes
        super AbstractArray[Byte]
 
        # A NativeString being a char*, it can be used as underlying representation here.
-       private var items: NativeString
+       var items: NativeString
 
        # Number of bytes in the array
        redef var length
@@ -63,6 +118,20 @@ class Bytes
                return items[i]
        end
 
+       # Returns self as a hexadecimal digest
+       fun hexdigest: String do
+               var elen = length * 2
+               var ns = new NativeString(elen)
+               var i = 0
+               var oi = 0
+               while i < length do
+                       self[i].add_digest_at(ns, oi)
+                       i += 1
+                       oi += 2
+               end
+               return new FlatString.full(ns, elen, 0, elen - 1, elen)
+       end
+
        #     var b = new Bytes.with_capacity(1)
        #     b[0] = 101u8
        #     assert b.to_s == "e"
@@ -146,80 +215,13 @@ class Bytes
        redef fun to_s do
                persisted = true
                var b = self
-               if not is_utf8 then
-                       b = clean_utf8
-                       persisted = false
-               end
-               return new FlatString.with_infos(b.items, b.length, 0, b.length -1)
+               var r = b.items.to_s_with_length(length)
+               if r != items then persisted = false
+               return r
        end
 
        redef fun iterator do return new BytesIterator.with_buffer(self)
 
-       # Is the byte collection valid UTF-8 ?
-       fun is_utf8: Bool do
-               var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8]
-               var lobounds = once [0, 0x80, 0x800, 0x10000]
-               var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF]
-               var pos = 0
-               var len = length
-               var mits = items
-               while pos < len do
-                       var nxst = mits.length_of_char_at(pos)
-                       var charst_index = (nxst - 1) * 2
-                       if mits[pos] & charst[charst_index] == charst[charst_index + 1] then
-                               var c = mits.char_at(pos)
-                               var cp = c.ascii
-                               if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then
-                                       if cp >= 0xD800 and cp <= 0xDFFF or
-                                          cp == 0xFFFE or cp == 0xFFFF then return false
-                               else
-                                       return false
-                               end
-                       else
-                               return false
-                       end
-                       pos += nxst
-               end
-               return true
-       end
-
-       # Cleans the bytes of `self` to be UTF-8 compliant
-       private fun clean_utf8: Bytes do
-               var charst = once [0x80u8, 0u8, 0xE0u8, 0xC0u8, 0xF0u8, 0xE0u8, 0xF8u8, 0xF0u8]
-               var badchar = once [0xEFu8, 0xBFu8, 0xBDu8]
-               var lobounds = once [0, 0x80, 0x800, 0x10000]
-               var hibounds = once [0x7F, 0x7FF, 0xFFFF, 0x10FFFF]
-               var pos = 0
-               var len = length
-               var ret = new Bytes.with_capacity(len)
-               var mits = items
-               while pos < len do
-                       var nxst = mits.length_of_char_at(pos)
-                       var charst_index = (nxst - 1) * 2
-                       if mits[pos] & charst[charst_index] == charst[charst_index + 1] then
-                               var c = mits.char_at(pos)
-                               var cp = c.ascii
-                               if cp <= hibounds[nxst - 1] and cp >= lobounds[nxst - 1] then
-                                       if cp >= 0xD800 and cp <= 0xDFFF or
-                                          cp == 0xFFFE or cp == 0xFFFF then
-                                               ret.append badchar
-                                               pos += 1
-                                       else
-                                               var pend = pos + nxst
-                                               for i in [pos .. pend[ do ret.add mits[i]
-                                               pos += nxst
-                                       end
-                               else
-                                       ret.append badchar
-                                       pos += 1
-                               end
-                       else
-                               ret.append badchar
-                               pos += 1
-                       end
-               end
-               return ret
-       end
 end
 
 private class BytesIterator
@@ -231,7 +233,7 @@ private class BytesIterator
 
        var max: Int
 
-       init with_buffer(b: Bytes) do init(b.items, 0, b.length - 1)
+       init with_buffer(b: Bytes) do init(b.items, 0, b.length)
 
        redef fun is_ok do return index < max
 
@@ -253,6 +255,15 @@ redef class Text
                return b
        end
 
+       # Is `self` a valid hexdigest ?
+       #
+       #     assert "0B1d3F".is_valid_hexdigest
+       #     assert not "5G".is_valid_hexdigest
+       fun is_valid_hexdigest: Bool do
+               for i in bytes do if not i.is_valid_hexdigit then return false
+               return true
+       end
+
        # Appends `self.bytes` to `b`
        fun append_to_bytes(b: Bytes) do
                for s in substrings do
@@ -260,6 +271,24 @@ redef class Text
                        b.append_ns_from(s.items, s.bytelen, from)
                end
        end
+
+       # Returns a new `Bytes` instance with the digest as content
+       #
+       #     assert "0B1F4D".hexdigest_to_bytes == [0x0Bu8, 0x1Fu8, 0x4Du8]
+       #
+       # REQUIRE: `self` is a valid hexdigest and hexdigest.length % 2 == 0
+       fun hexdigest_to_bytes: Bytes do
+               var b = bytes
+               var pos = 0
+               var max = bytelen
+               var ret = new Bytes.with_capacity(max / 2)
+               while pos < max do
+                       ret.add((b[pos].hexdigit_to_byteval << 4) |
+                       b[pos + 1].hexdigit_to_byteval)
+                       pos += 2
+               end
+               return ret
+       end
 end
 
 redef class FlatText
index 2db319a..4b1e826 100644 (file)
@@ -173,12 +173,13 @@ abstract class Reader
        # ~~~
        fun read_all: String do
                var s = read_all_bytes
-               if not s.is_utf8 then s = s.clean_utf8
                var slen = s.length
                if slen == 0 then return ""
                var rets = ""
                var pos = 0
-               var sits = s.items
+               var str = s.items.clean_utf8(slen)
+               slen = str.bytelen
+               var sits = str.items
                var remsp = slen
                while pos < slen do
                        # The 129 size was decided more or less arbitrarily
index c8b6ecd..52de988 100644 (file)
@@ -985,8 +985,7 @@ redef class NativeString
        redef fun to_s_with_length(length): FlatString
        do
                assert length >= 0
-               var str = new FlatString.with_infos(self, length, 0, length - 1)
-               return str
+               return clean_utf8(length)
        end
 
        redef fun to_s_full(bytelen, unilen) do
@@ -997,6 +996,8 @@ redef class NativeString
        redef fun to_s_with_copy: FlatString
        do
                var length = cstring_length
+               var r = clean_utf8(length)
+               if r.items != self then return r
                var new_self = new NativeString(length + 1)
                copy_to(new_self, length, 0, 0)
                var str = new FlatString.with_infos(new_self, length, 0, length - 1)
@@ -1005,6 +1006,81 @@ redef class NativeString
                return str
        end
 
+       # Cleans a NativeString if necessary
+       fun clean_utf8(len: Int): FlatString do
+               var replacements: nullable Array[Int] = null
+               var end_length = len
+               var pos = 0
+               var chr_ln = 0
+               while pos < len do
+                       var b = self[pos]
+                       var nxst = length_of_char_at(pos)
+                       var ok_st: Bool
+                       if nxst == 1 then
+                               ok_st = b & 0x80u8 == 0u8
+                       else if nxst == 2 then
+                               ok_st = b & 0xE0u8 == 0xC0u8
+                       else if nxst == 3 then
+                               ok_st = b & 0xF0u8 == 0xE0u8
+                       else
+                               ok_st = b & 0xF8u8 == 0xF0u8
+                       end
+                       if not ok_st then
+                               if replacements == null then replacements = new Array[Int]
+                               replacements.add pos
+                               end_length += 2
+                               pos += 1
+                               chr_ln += 1
+                               continue
+                       end
+                       var ok_c: Bool
+                       var c = char_at(pos)
+                       var cp = c.ascii
+                       if nxst == 1 then
+                               ok_c = cp >= 0 and cp <= 0x7F
+                       else if nxst == 2 then
+                               ok_c = cp >= 0x80 and cp <= 0x7FF
+                       else if nxst == 3 then
+                               ok_c = cp >= 0x800 and cp <= 0xFFFF
+                               ok_c = ok_c and not (cp >= 0xD800 and cp <= 0xDFFF) and cp != 0xFFFE and cp != 0xFFFF
+                       else
+                               ok_c = cp >= 0x10000 and cp <= 0x10FFFF
+                       end
+                       if not ok_c then
+                               if replacements == null then replacements = new Array[Int]
+                               replacements.add pos
+                               end_length += 2
+                               pos += 1
+                               chr_ln += 1
+                               continue
+                       end
+                       pos += c.u8char_len
+                       chr_ln += 1
+               end
+               var ret = self
+               if end_length != len then
+                       ret = new NativeString(end_length)
+                       var old_repl = 0
+                       var off = 0
+                       var repls = replacements.as(not null)
+                       var r = repls.items.as(not null)
+                       var imax = repls.length
+                       for i in [0 .. imax[ do
+                               var repl_pos = r[i]
+                               var chkln = repl_pos - old_repl
+                               copy_to(ret, chkln, old_repl, off)
+                               off += chkln
+                               ret[off] = 0xEFu8
+                               ret[off + 1] = 0xBFu8
+                               ret[off + 2] = 0xBDu8
+                               old_repl = repl_pos + 1
+                               off += 3
+                       end
+                       copy_to(ret, len - old_repl, old_repl, off)
+               end
+               return new FlatString.full(ret, end_length, 0, end_length - 1, chr_ln)
+       end
+
        # Sets the next bytes at position `pos` to the value of `c`, encoded in UTF-8
        #
        # Very unsafe, make sure to have room for this char prior to calling this function.
@@ -1109,7 +1185,7 @@ redef class Array[E]
                        end
                        i += 1
                end
-               return ns.to_s_with_length(sl)
+               return new FlatString.with_infos(ns, sl, 0, sl - 1)
        end
 end
 
@@ -1146,7 +1222,7 @@ redef class NativeArray[E]
                        end
                        i += 1
                end
-               return ns.to_s_with_length(sl)
+               return new FlatString.with_infos(ns, sl, 0, sl - 1)
        end
 end
 
diff --git a/lib/gamnit/display.nit b/lib/gamnit/display.nit
new file mode 100644 (file)
index 0000000..94ece8a
--- /dev/null
@@ -0,0 +1,49 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Abstract display services
+module display
+
+import ::glesv2
+
+import display_linux is conditional(linux)
+import display_android is conditional(android)
+
+# Should Gamnit be more verbose?
+fun debug_gamnit: Bool do return false
+
+# General display class, is sized and drawable
+class GamnitDisplay
+
+       # Width of the display, in pixels
+       fun width: Int is abstract
+
+       # Height of the display, in pixels
+       fun height: Int is abstract
+
+       # Prepare this display
+       #
+       # The implementation varies per platform.
+       fun setup is abstract
+
+       # Close this display and free underlying resources
+       #
+       # The implementation varies per platform.
+       fun close do end
+
+       # Flip the display buffers
+       #
+       # The implementation varies per platform.
+       fun flip do end
+end
diff --git a/lib/gamnit/display_android.nit b/lib/gamnit/display_android.nit
new file mode 100644 (file)
index 0000000..d0e5235
--- /dev/null
@@ -0,0 +1,47 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Gamnit display implementation for Android
+#
+# Generated APK files require OpenGL ES 2.0.
+#
+# This modules uses `android::native_app_glue` and the Android NDK.
+module display_android is
+       android_manifest """<uses-feature android:glEsVersion="0x00020000"/>"""
+end
+
+import ::android
+
+private import gamnit::egl
+
+redef class GamnitDisplay
+
+       redef fun setup
+       do
+               var native_display = egl_default_display
+               var native_window = app.native_app_glue.window
+
+               setup_egl_display native_display
+
+               # We need 8 bits per color for selection by color
+               select_egl_config(8, 8, 8, 0, 8, 0, 0)
+
+               var format = egl_config.attribs(egl_display).native_visual_id
+               native_window.set_buffers_geometry(0, 0, format)
+
+               setup_egl_context native_window
+       end
+
+       redef fun close do close_egl
+end
diff --git a/lib/gamnit/display_linux.nit b/lib/gamnit/display_linux.nit
new file mode 100644 (file)
index 0000000..109ff51
--- /dev/null
@@ -0,0 +1,91 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Gamnit display implementation for GNU/Linux using `egl`, `sdl` and `x11`
+module display_linux
+
+import sdl
+import x11
+
+import egl # local to gamnit
+import display
+
+redef class GamnitDisplay
+
+       # Actual width or desired width of the window, can be set before calling `setup`
+       fun width=(value: Int) do requested_width = value
+       private var requested_width = 1920
+
+       # Actual height or desired height of the window, can be set before calling `setup`
+       fun height=(value: Int) do requested_height = value
+       private var requested_height = 1080
+
+       # Setup SDL, X11, EGL in order
+       redef fun setup
+       do
+               if debug_gamnit then print "Setting up SDL"
+               self.sdl_display = setup_sdl(requested_width, requested_height)
+
+               if debug_gamnit then print "Setting up X11"
+               var x11_display = setup_x11
+               var window_handle = window_handle
+               setup_egl_display x11_display
+
+               if debug_gamnit then print "Setting up EGL context"
+               select_egl_config(8, 8, 8, 8, 8, 0, 0)
+               setup_egl_context window_handle
+       end
+
+       # Close EGL and SDL in reverse order of `setup` (nothing to do for X11)
+       redef fun close
+       do
+               close_egl
+               close_sdl
+       end
+
+       # ---
+       # SDL
+
+       # The SDL display managing the window and events
+       var sdl_display: SDLDisplay is noautoinit
+
+       # Setup the SDL display and lib
+       fun setup_sdl(window_width, window_height: Int): SDLDisplay
+       do
+               var sdl_display = new SDLDisplay(window_width, window_height)
+               assert not sdl_display.address_is_null else print "Opening SDL display failed"
+               return sdl_display
+       end
+
+       # Close the SDL display
+       fun close_sdl do sdl_display.destroy
+
+       # Get a native handle to the current SDL window
+       fun window_handle: Pointer
+       do
+               var sdl_wm_info = new SDLSystemWindowManagerInfo
+               return sdl_wm_info.x11_window_handle
+       end
+
+       # ---
+       # X11
+
+       # Get a native handle to the current X11 display
+       fun setup_x11: Pointer
+       do
+               var x11_display = x_open_default_display
+               assert not x11_display.address_is_null else print "Opening X11 display failed"
+               return x11_display
+       end
+end
diff --git a/lib/gamnit/egl.nit b/lib/gamnit/egl.nit
new file mode 100644 (file)
index 0000000..3fcb8c8
--- /dev/null
@@ -0,0 +1,115 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Use of EGL to implement Gamnit on GNU/Linux and Android
+module egl
+
+import ::egl
+
+import gamnit::display
+
+redef class GamnitDisplay
+
+       # The EGL display
+       var egl_display: EGLDisplay is noautoinit
+
+       # The EGL context
+       var egl_context: EGLContext is noautoinit
+
+       # The EGL surface for the window
+       var window_surface: EGLSurface is noautoinit
+
+       # The selected EGL configuration
+       var egl_config: EGLConfig is noautoinit
+
+       # Setup the EGL display for the given `x11_display`
+       protected fun setup_egl_display(x11_display: Pointer)
+       do
+               var egl_display = new EGLDisplay(x11_display)
+               assert egl_display.is_valid else print "new EGL display is not valid"
+
+               egl_display.initialize
+               assert egl_display.is_valid else print "EGL initialize error: {egl_display.error}"
+
+               self.egl_display = egl_display
+       end
+
+       # Select an EGL config
+       protected fun select_egl_config(blue, green, red, alpha, depth, stencil, sample: Int)
+       do
+               var config_chooser = new EGLConfigChooser
+               config_chooser.renderable_type_egl
+               config_chooser.surface_type_egl
+               config_chooser.blue_size = blue
+               config_chooser.green_size = green
+               config_chooser.red_size = red
+               if alpha > 0 then config_chooser.alpha_size = alpha
+               if depth > 0 then config_chooser.depth_size = depth
+               if stencil > 0 then config_chooser.stencil_size = stencil
+               if sample > 0 then config_chooser.sample_buffers = sample
+               config_chooser.close
+
+               var configs = config_chooser.choose(egl_display)
+               assert configs != null else print "Choosing EGL config failed: {egl_display.error}"
+               assert not configs.is_empty else print "Found no EGL config"
+
+               if debug_gamnit then
+                       print "EGL available configurations:"
+                       for config in configs do
+                               var attribs = config.attribs(egl_display)
+                               print "* Conformant to: {attribs.conformant}"
+                               print "  Caveats: {attribs.caveat}"
+                               print "  Size of RGBA: {attribs.red_size} {attribs.green_size} {attribs.blue_size} {attribs.alpha_size}"
+                               print "  Buffer, depth, stencil: {attribs.buffer_size} {attribs.depth_size} {attribs.stencil_size}"
+                       end
+               end
+
+               # We use the first one, it is recommended
+               self.egl_config = configs.first
+       end
+
+       # Setup the EGL context for the given `window_handle`
+       protected fun setup_egl_context(window_handle: Pointer)
+       do
+               var window_surface = egl_display.create_window_surface(egl_config, window_handle, [0])
+               assert window_surface.is_ok else print "Creating EGL window surface failed: {egl_display.error}"
+               self.window_surface = window_surface
+
+               egl_context = egl_display.create_context(egl_config)
+               assert egl_context.is_ok else print "Creating EGL context failed: {egl_display.error}"
+
+               var make_current_res = egl_display.make_current(window_surface, window_surface, egl_context)
+               assert make_current_res else print "Creating EGL make current failed: {egl_display.error}"
+
+               # TODO make the API selection configurable per platform
+               assert egl_bind_opengl_es_api else print "EGL bind API failed: {egl_display.error}"
+       end
+
+       redef fun width do return window_surface.attribs(egl_display).width
+
+       redef fun height do return window_surface.attribs(egl_display).height
+
+       # Close the EGL context
+       fun close_egl
+       do
+               egl_display.make_current(new EGLSurface.none, new EGLSurface.none, new EGLContext.none)
+               egl_display.destroy_context(egl_context)
+               egl_display.destroy_surface(window_surface)
+       end
+
+       redef fun flip
+       do
+               egl_display.swap_buffers(window_surface)
+       end
+end
diff --git a/lib/gamnit/examples/triangle/Makefile b/lib/gamnit/examples/triangle/Makefile
new file mode 100644 (file)
index 0000000..22172de
--- /dev/null
@@ -0,0 +1,21 @@
+NITC=../../../../bin/nitc
+NITLS=../../../../bin/nitls
+
+all: bin/standalone_triangle bin/triangle bin/triangle.apk
+
+bin/standalone_triangle: $(shell ${NITLS} -M src/standalone_triangle.nit linux) ${NITC}
+       ${NITC} src/standalone_triangle.nit -m linux -o $@
+
+bin/triangle: $(shell ${NITLS} -M src/portable_triangle.nit linux) ${NITC}
+       ${NITC} src/portable_triangle.nit -m linux -o $@
+
+check: bin/standalone_triangle bin/triangle
+       bin/standalone_triangle
+       bin/triangle
+
+android: bin/triangle.apk
+bin/triangle.apk: $(shell ${NITLS} -M src/portable_triangle.nit android) ${NITC} res/drawable-hdpi/icon.png
+       ${NITC} src/portable_triangle.nit -m android -o $@
+
+res/drawable-hdpi/icon.png: art/icon.svg
+       ../../../../contrib/inkscape_tools/bin/svg_to_icons --out res --android art/icon.svg
diff --git a/lib/gamnit/examples/triangle/art/icon.svg b/lib/gamnit/examples/triangle/art/icon.svg
new file mode 100644 (file)
index 0000000..26f7c04
--- /dev/null
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="512"
+   height="512"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.5 r10040"
+   sodipodi:docname="New document 1">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="292.54393"
+     inkscape:cy="311.81525"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1279"
+     inkscape:window-height="1379"
+     inkscape:window-x="3840"
+     inkscape:window-y="27"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(0,-540.36218)">
+    <rect
+       style="fill:#ab00cf;fill-opacity:1;stroke:none"
+       id="rect2985"
+       width="512"
+       height="512"
+       x="0"
+       y="540.36218"
+       ry="69.507881"
+       rx="69.507881" />
+    <path
+       sodipodi:type="star"
+       style="fill:#ff001b;fill-opacity:1;stroke:none"
+       id="path3755"
+       sodipodi:sides="3"
+       sodipodi:cx="22.857143"
+       sodipodi:cy="-299.06638"
+       sodipodi:r1="235.13782"
+       sodipodi:r2="118.85303"
+       sodipodi:arg1="-1.5707963"
+       sodipodi:arg2="-0.52359875"
+       inkscape:flatsided="false"
+       inkscape:rounded="0"
+       inkscape:randomized="0"
+       d="m 22.85715,-534.20419 102.92974,175.7113 100.70557,176.99543 -203.63532,1.28411 -203.63532,-1.28412 100.705584,-176.99542 z"
+       inkscape:transform-center-y="-22.453664"
+       transform="translate(232.85714,1144.2857)" />
+  </g>
+</svg>
diff --git a/lib/gamnit/examples/triangle/bin/.gitignore b/lib/gamnit/examples/triangle/bin/.gitignore
new file mode 100644 (file)
index 0000000..72e8ffc
--- /dev/null
@@ -0,0 +1 @@
+*
diff --git a/lib/gamnit/examples/triangle/package.ini b/lib/gamnit/examples/triangle/package.ini
new file mode 100644 (file)
index 0000000..f673878
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name=triangle
+tags=example
+maintainer=Alexis Laferrière <alexis.laf@xymus.net>
+license=Apache-2.0
+[upstream]
+browse=https://github.com/nitlang/nit/tree/master/lib/gamnit/examples/triangle/
+git=https://github.com/nitlang/nit.git
+git.directory=lib/gamnit/examples/triangle/
+homepage=http://nitlanguage.org
+issues=https://github.com/nitlang/nit/issues
diff --git a/lib/gamnit/examples/triangle/res/.gitignore b/lib/gamnit/examples/triangle/res/.gitignore
new file mode 100644 (file)
index 0000000..72e8ffc
--- /dev/null
@@ -0,0 +1 @@
+*
diff --git a/lib/gamnit/examples/triangle/src/portable_triangle.nit b/lib/gamnit/examples/triangle/src/portable_triangle.nit
new file mode 100644 (file)
index 0000000..ac8e0e6
--- /dev/null
@@ -0,0 +1,138 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Portable example of using Gamnit with custom calls to OpenGL ES 2.0
+#
+# References:
+# * The book OpenGL ES 2.0 Programming Guide
+# * https://code.google.com/p/opengles-book-samples/source/browse/trunk/LinuxX11/Chapter_2/Hello_Triangle/Hello_Triangle.c
+module portable_triangle is
+       app_name "gamnit Triangle"
+       app_namespace "org.nitlanguage.triangle"
+       app_version(1, 0, git_revision)
+end
+
+import gamnit
+
+redef class App
+
+       # Our only program for the graphic card
+       var program: GLProgram is noautoinit
+
+       # The only vertex sharder
+       var vertex_shader: GLVertexShader is noautoinit
+
+       # The only fragment sharder
+       var fragment_shader: GLFragmentShader is noautoinit
+
+       # Vertex data for the triangle
+       var vertex_array: VertexArray is noautoinit
+
+       redef fun on_create
+       do
+               super
+
+               var display = display
+               assert display != null
+
+               print "Width: {display.width}"
+               print "Height: {display.height}"
+
+               assert_no_gl_error
+               assert gl.shader_compiler else print "Cannot compile shaders"
+
+               # GL program
+               program = new GLProgram
+               if not program.is_ok then
+                       print "Program is not ok: {gl.error.to_s}\nLog:"
+                       print program.info_log
+                       abort
+               end
+               assert_no_gl_error
+
+               # Vertex shader
+               vertex_shader = new GLVertexShader
+               assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl.error}"
+               vertex_shader.source = """
+               attribute vec4 vPosition;
+               void main()
+               {
+                 gl_Position = vPosition;
+               }
+               """@glsl_vertex_shader.to_cstring
+               vertex_shader.compile
+               assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}"
+               assert_no_gl_error
+
+               # Fragment shader
+               fragment_shader = new GLFragmentShader
+               assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl.error}"
+               fragment_shader.source = """
+               precision mediump float;
+               void main()
+               {
+                       gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+               }
+               """@glsl_fragment_shader.to_cstring
+               fragment_shader.compile
+               assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}"
+               assert_no_gl_error
+
+               # Attach to program
+               program.attach_shader vertex_shader
+               program.attach_shader fragment_shader
+               program.bind_attrib_location(0, "vPosition")
+               program.link
+               assert program.is_linked else print "Linking failed: {program.info_log}"
+               assert_no_gl_error
+
+               # Draw!
+               var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0]
+               vertex_array = new VertexArray(0, 3, vertices)
+               vertex_array.attrib_pointer
+       end
+
+       redef fun frame_core
+       do
+               var display = display
+               if display != null then
+                       gl.clear_color(0.5, 0.0, 0.5, 1.0)
+
+                       assert_no_gl_error
+                       gl.viewport(0, 0, display.width, display.height)
+                       gl.clear((new GLBuffer).color)
+                       program.use
+                       vertex_array.enable
+
+                       glDrawArrays(new GLDrawMode.triangles, 0, 3)
+
+                       display.flip
+               end
+       end
+
+       redef fun on_stop
+       do
+               # Clean up
+               program.delete
+               vertex_shader.delete
+               fragment_shader.delete
+
+               # Close gamnit
+               var display = display
+               if display != null then display.close
+       end
+end
+
+if "NIT_TESTING".environ == "true" then exit(0)
+super
diff --git a/lib/gamnit/examples/triangle/src/standalone_triangle.nit b/lib/gamnit/examples/triangle/src/standalone_triangle.nit
new file mode 100644 (file)
index 0000000..04e14db
--- /dev/null
@@ -0,0 +1,112 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Example of using `GamnitDisplay` to setup a screen for custom calls to OpenGL ES 2.0
+#
+# This example does not support the lifecycle of mobile platforms, as such it only works on desktop computers.
+#
+# References:
+# * The book OpenGL ES 2.0 Programming Guide
+# * https://code.google.com/p/opengles-book-samples/source/browse/trunk/LinuxX11/Chapter_2/Hello_Triangle/Hello_Triangle.c
+module standalone_triangle
+
+import app
+import gamnit::display
+
+if "NIT_TESTING".environ == "true" then exit(0)
+
+# Setup gamnit
+var display = new GamnitDisplay
+display.setup
+
+var width = display.width
+var height = display.height
+print "Width: {width}"
+print "Height: {height}"
+
+# Custom calls to OpenGL ES 2.0
+assert_no_gl_error
+assert gl.shader_compiler else print "Cannot compile shaders"
+
+# GL program
+print gl.error.to_s
+var program = new GLProgram
+if not program.is_ok then
+       print "Program is not ok: {gl.error.to_s}\nLog:"
+       print program.info_log
+       abort
+end
+assert_no_gl_error
+
+# Vertex shader
+var vertex_shader = new GLVertexShader
+assert vertex_shader.is_ok else print "Vertex shader is not ok: {gl.error}"
+vertex_shader.source = """
+attribute vec4 vPosition;
+void main()
+{
+  gl_Position = vPosition;
+}
+"""@glsl_vertex_shader.to_cstring
+vertex_shader.compile
+assert vertex_shader.is_compiled else print "Vertex shader compilation failed with: {vertex_shader.info_log} {program.info_log}"
+assert_no_gl_error
+
+# Fragment shader
+var fragment_shader = new GLFragmentShader
+assert fragment_shader.is_ok else print "Fragment shader is not ok: {gl.error}"
+fragment_shader.source = """
+precision mediump float;
+void main()
+{
+       gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+}
+"""@glsl_fragment_shader.to_cstring
+fragment_shader.compile
+assert fragment_shader.is_compiled else print "Fragment shader compilation failed with: {fragment_shader.info_log}"
+assert_no_gl_error
+
+# Attach to program
+program.attach_shader vertex_shader
+program.attach_shader fragment_shader
+program.bind_attrib_location(0, "vPosition")
+program.link
+assert program.is_linked else print "Linking failed: {program.info_log}"
+assert_no_gl_error
+
+# Draw!
+var vertices = [0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0]
+var vertex_array = new VertexArray(0, 3, vertices)
+vertex_array.attrib_pointer
+gl.clear_color(0.5, 0.0, 0.5, 1.0)
+for i in [0..1000[ do
+       printn "."
+       assert_no_gl_error
+       gl.viewport(0, 0, width, height)
+       gl.clear((new GLBuffer).color)
+       program.use
+       vertex_array.enable
+
+       glDrawArrays(new GLDrawMode.triangles, 0, 3)
+
+       display.flip
+end
+
+# Clean up
+program.delete
+vertex_shader.delete
+fragment_shader.delete
+
+# Close gamnit
+display.close
index 2fa5b8e..43ec95c 100644 (file)
 
 # Game and multimedia framework for Nit
 module gamnit
+
+import app
+
+import display
+
+import gamnit_android is conditional(android)
+
+redef class App
+
+       # Main `GamnitDisplay` initialized by `on_create`
+       var display: nullable GamnitDisplay = null
+
+       redef fun on_create
+       do
+               super
+
+               var display = new GamnitDisplay
+               display.setup
+               self.display = display
+       end
+
+       # Core of the frame logic, executed only when the display is visible
+       #
+       # This method should be redefined by user modules to customize the behavior of the game.
+       protected fun frame_core do end
+
+       # Full frame logic, executed even if the display is not visible
+       #
+       # This method wraps `frame_core` and other services to be executed in the main app loop.
+       #
+       # To customize the behavior on each turn, it is preferable to redefined `frame_core`.
+       # Still, `frame_full` can be redefined with care for more control.
+       protected fun frame_full
+       do
+               var display = display
+               if display != null then frame_core
+
+               feed_events
+       end
+
+       redef fun run
+       do
+               # TODO manage exit condition
+               loop frame_full
+       end
+
+       # Loop on available events and feed them back to the app
+       #
+       # The implementation varies per platform.
+       private fun feed_events do end
+end
diff --git a/lib/gamnit/gamnit_android.nit b/lib/gamnit/gamnit_android.nit
new file mode 100644 (file)
index 0000000..647c741
--- /dev/null
@@ -0,0 +1,24 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Support services for Gamnit on Android
+module gamnit_android
+
+import android
+
+intrude import gamnit
+
+redef class App
+       redef fun feed_events do app.poll_looper 0
+end
index 8b90102..04a0c5d 100644 (file)
 module linux
 
 import app
+
+redef class App
+       redef fun setup
+       do
+               super
+
+               on_create
+               on_restore_state
+               on_start
+               on_resume
+       end
+
+       redef fun run
+       do
+               super
+
+               on_pause
+               on_save_state
+               on_stop
+               on_destroy
+       end
+end
index 938bfd8..7bc03a0 100644 (file)
@@ -35,21 +35,6 @@ redef class App
                display = new Opengles1Display
 
                super
-
-               on_create
-               on_restore_state
-               on_start
-               on_resume
-       end
-
-       redef fun run
-       do
-               super
-
-               on_pause
-               on_save_state
-               on_stop
-               on_destroy
        end
 
        redef fun generate_input
index 8a5acc9..2bd8fbe 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT (http://www.nitlanguage.org).
 #
-# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com>
-#
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
@@ -219,22 +217,12 @@ in "C Header" `{
        }
 `}
 
-redef class String
-
-       # Computes the SHA1 of the receiver
-       #
-       # Returns a digest of 20 bytes as a String,
-       # note that all the characters are not necessarily ASCII.
-       # If you want the hex string version of the digest, use
-       # sha1_to_s.
-       #
-       #     import base64
-       #     assert "The quick brown fox jumps over the lazy dog".sha1.encode_base64 == "L9ThxnotKPzthJ7hu3bnORuT6xI="
-       fun sha1: String import String.to_cstring, String.length, NativeString.to_s_with_length `{
+redef class NativeString
+       private fun sha1_intern(len: Int): NativeString `{
                sha1nfo s;
 
                sha1_init(&s);
-               sha1_write(&s, String_to_cstring(self), String_length(self));
+               sha1_write(&s, self, len);
                uint8_t* digest = sha1_result(&s);
 
                char* digested = malloc(21);
@@ -243,35 +231,30 @@ redef class String
 
                digested[20] = '\0';
 
-               return NativeString_to_s_with_length(digested, 20);
+               return digested;
        `}
+end
+
+redef class String
+
+       # Computes the SHA1 of the receiver
+       #
+       # Returns a digest of 20 bytes as a NativeString,
+       # note that all the characters are not necessarily ASCII.
+       # If you want the hex string version of the digest, use
+       # sha1_hexdigest.
+       #
+       #     import base64
+       #     assert "The quick brown fox jumps over the lazy dog".sha1 == [0x2Fu8, 0xD4u8, 0xE1u8, 0xC6u8, 0x7Au8, 0x2Du8, 0x28u8, 0xFCu8, 0xEDu8, 0x84u8, 0x9Eu8, 0xE1u8, 0xBBu8, 0x76u8, 0xE7u8, 0x39u8, 0x1Bu8, 0x93u8, 0xEBu8, 0x12u8]
+       fun sha1: Bytes do
+               return new Bytes(to_cstring.sha1_intern(bytelen), 20, 20)
+       end
 
        # Computes the SHA1 of the receiver.
        #
        # Returns a 40 char String containing the Hexadecimal
        # Digest in its Char form.
        #
-       #     assert "The quick brown fox jumps over the lazy dog".sha1_to_s == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"
-       fun sha1_to_s: String import String.to_cstring, String.length, NativeString.to_s_with_length `{
-               sha1nfo s;
-
-               sha1_init(&s);
-               sha1_write(&s, String_to_cstring(self), String_length(self));
-               uint8_t* digest = sha1_result(&s);
-
-               char* ret_str = malloc(41);
-               char* hexmap = "0123456789ABCDEF";
-
-               int i;
-               for(i=0;i<20;i++){
-                       uint8_t q = digest[i];
-                       ret_str[i*2] = hexmap[q >> 4];
-                       ret_str[(i*2)+1] = hexmap[q & 0x0F];
-               }
-               ret_str[40] = '\0';
-
-               return NativeString_to_s_with_length(ret_str, 40);
-       `}
-
+       #     assert "The quick brown fox jumps over the lazy dog".sha1_hexdigest == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"
+       fun sha1_hexdigest: String do return sha1.hexdigest
 end
-
index c3fdaad..2a3c32f 100644 (file)
@@ -114,7 +114,7 @@ class WebsocketConnection
                resp_map["Connection:"] = "Upgrade"
                var key = heads["Sec-WebSocket-Key"]
                key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
-               key = key.sha1.encode_base64
+               key = key.sha1.encode_base64.to_s
                resp_map["Sec-WebSocket-Accept:"] = key
                var resp = resp_map.join("\r\n", " ")
                resp += "\r\n\r\n"
index edf0a16..79c2f14 100644 (file)
@@ -280,7 +280,7 @@ redef class MExplicitCast
 
                        var from_var = nitni_visitor.var_from_c("from", from)
                        from_var = nitni_visitor.box_extern(from_var, from)
-                       var recv_var = nitni_visitor.type_test(from_var, to, "FFI isa")
+                       var recv_var = nitni_visitor.type_test(from_var, to, "isa")
                        nitni_visitor.add("return {recv_var};")
 
                        nitni_visitor.add("\}")
@@ -316,7 +316,7 @@ redef class MExplicitCast
                        from_var = nitni_visitor.box_extern(from_var, from)
 
                        ## test type
-                       var check = nitni_visitor.type_test(from_var, to, "FFI cast")
+                       var check = nitni_visitor.type_test(from_var, to, "as")
                        nitni_visitor.add("if (!{check}) \{")
                        nitni_visitor.add_abort("FFI cast failed")
                        nitni_visitor.add("\}")
index 1066456..ff641cc 100644 (file)
@@ -21,7 +21,7 @@ Calls to bytepos for each type:
        FlatString = 18
 Calls to first_byte on FlatString 153
 Calls to last_byte on FlatString 103
-FlatStrings allocated with length 81 (85.417%)
+FlatStrings allocated with length 82 (86.458%)
 Length of travel for index distribution:
 * null = 20 => occurences 83.333%, cumulative 83.333% 
 * 1 = 8 => occurences 21.053%, cumulative 73.684% 
index fe675df..ce7118b 100644 (file)
@@ -13,6 +13,7 @@ redef class Deserializer
                if name == "Array[nullable Object]" then return new Array[nullable Object].from_deserializer(self)
                if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self)
                if name == "Array[Object]" then return new Array[Object].from_deserializer(self)
+               if name == "Array[Int]" then return new Array[Int].from_deserializer(self)
                if name == "Array[Match]" then return new Array[Match].from_deserializer(self)
                if name == "Array[nullable Match]" then return new Array[nullable Match].from_deserializer(self)
                return super
diff --git a/tests/sav/test_bytes_hexdigit.res b/tests/sav/test_bytes_hexdigit.res
new file mode 100644 (file)
index 0000000..f00af0c
--- /dev/null
@@ -0,0 +1,3 @@
+0x0b
+0x1f
+0x4d
index 49e9adc..f6e7b69 100644 (file)
@@ -21,7 +21,7 @@ Calls to bytepos for each type:
        FlatString = 18
 Calls to first_byte on FlatString 153
 Calls to last_byte on FlatString 103
-FlatStrings allocated with length 81 (85.417%)
+FlatStrings allocated with length 82 (86.458%)
 Length of travel for index distribution:
 * 0 = 20 => occurences 83.333%, cumulative 83.333% 
 * 1 = 8 => occurences 21.053%, cumulative 73.684% 
diff --git a/tests/test_bytes_hexdigit.nit b/tests/test_bytes_hexdigit.nit
new file mode 100644 (file)
index 0000000..28f51e3
--- /dev/null
@@ -0,0 +1,17 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var s = "0B1F4D".hexdigest_to_bytes
+
+for i in s do print i